/*
 * Copyright 2006-2019 Dave Griffith, Bas Leijdekkers
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.siyeh.ig.bugs;

import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.InspectionGadgetsFix;
import com.siyeh.ig.PsiReplacementUtil;
import com.siyeh.ig.callMatcher.CallMatcher;
import com.siyeh.ig.psiutils.ExpressionUtils;
import org.intellij.lang.annotations.Pattern;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class ReplaceAllDotInspection extends BaseInspection {

  @Override
  @NotNull
  public String buildErrorString(Object... infos) {
    final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)infos[0];
    final String methodName = methodCallExpression.getMethodExpression().getReferenceName();
    return InspectionGadgetsBundle.message("replace.all.dot.problem.descriptor", methodName);
  }

  @Override
  public boolean isEnabledByDefault() {
    return true;
  }

  @Pattern(VALID_ID_PATTERN)
  @NotNull
  @Override
  public String getID() {
    return "SuspiciousRegexArgument";
  }

  @Nullable
  @Override
  public String getAlternativeID() {
    return "ReplaceAllDot";
  }

  @Nullable
  @Override
  protected InspectionGadgetsFix buildFix(Object... infos) {
    final PsiExpression expression = (PsiExpression)infos[1];
    if (!(expression instanceof PsiLiteralExpression)) {
      return null;
    }
    return new EscapeCharacterFix();
  }

  private static class EscapeCharacterFix extends InspectionGadgetsFix {

    @Nls(capitalization = Nls.Capitalization.Sentence)
    @NotNull
    @Override
    public String getFamilyName() {
      return InspectionGadgetsBundle.message("replace.all.dot.quickfix");
    }

    @Override
    protected void doFix(Project project, ProblemDescriptor descriptor) {
      final PsiElement element = descriptor.getPsiElement();
      if (!(element instanceof PsiExpression)) {
        return;
      }
      final PsiExpression expression = (PsiExpression)element;
      final String text = expression.getText();

      PsiReplacementUtil.replaceExpression(expression, text.substring(0, 1) + "\\\\" + text.substring(1));
    }
  }

  @Override
  public BaseInspectionVisitor buildVisitor() {
    return new ReplaceAllDotVisitor();
  }

  private static class ReplaceAllDotVisitor extends BaseInspectionVisitor {

    private static final CallMatcher.Simple MATCHER = CallMatcher.instanceCall(CommonClassNames.JAVA_LANG_STRING, "replaceAll", "split");

    @Override
    public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression) {
      super.visitMethodCallExpression(expression);
      if (!MATCHER.test(expression)) {
        return;
      }
      final PsiExpression argument = expression.getArgumentList().getExpressions()[0];
      if (!PsiUtil.isConstantExpression(argument) || !ExpressionUtils.hasStringType(argument)) {
        return;
      }
      final String value = (String)ExpressionUtils.computeConstantExpression(argument);
      if (!isRegexMetaChar(value)) {
        return;
      }
      registerError(argument, expression, argument);
    }

    private static boolean isRegexMetaChar(String s) {
      return s != null && s.length() == 1 && ".$|()[{^?*+\\".contains(s);
    }
  }
}
@@ -20,10 +20,10 @@
 6-20
-19
+20
  Dav
@@ -735,16 +735,66 @@
 roject;%0A
+import com.intellij.openapi.util.text.StringUtil;%0A
 import c
@@ -846,24 +846,60 @@
 il.PsiUtil;%0A
+import com.intellij.util.ArrayUtil;%0A
 import com.s
@@ -1413,16 +1413,83 @@
 tion %7B%0A%0A
+  private static final String REGEX_META_CHARS = %22.$%7C()%5B%7B%5E?*+%5C%5C%22;%0A%0A
   @Overr
@@ -2851,24 +2851,31 @@
 stanceof Psi
+Literal
 Expression))
@@ -2908,32 +2908,39 @@
 %0A      final Psi
+Literal
 Expression expre
@@ -2943,32 +2943,39 @@
 xpression = (Psi
+Literal
 Expression)eleme
@@ -3026,16 +3026,337 @@
 Text();%0A
+      final StringBuilder newExpression = new StringBuilder();%0A      int length = text.length();%0A      for (int i = 0; i %3C length; i++) %7B%0A        char c = text.charAt(i);%0A        if (StringUtil.containsChar(REGEX_META_CHARS, c)) %7B%0A          newExpression.append(%22%5C%5C%5C%5C%22);%0A        %7D%0A        newExpression.append(c);%0A      %7D
 %0A      P
@@ -3407,56 +3407,31 @@
 on, 
-text.substring(0, 1) + %22%5C%5C%5C%5C%22 + text.subs
+newExpression.toS
 tring(
-1
 ));%0A
@@ -4011,24 +4011,50 @@
  argument = 
+ArrayUtil.getFirstElement(
 expression.g
@@ -4086,19 +4086,17 @@
 ssions()
-%5B0%5D
+)
 ;%0A      
@@ -4330,16 +4330,31 @@
 ar(value
+, !isOnTheFly()
 )) %7B%0A   
@@ -4485,16 +4485,39 @@
 String s
+, boolean includeErrors
 ) %7B%0A    
@@ -4557,31 +4557,59 @@
 == 1 && 
-%22.$%7C()%5B%7B%5E?*+%5C%5C%22
+(includeErrors ? REGEX_META_CHARS : %22.$%7C%5E%22)
 .contain

fix suspicious regex string arguments problems (IDEA-CR-57083)