Пример #1
0
  static void addOwnDataTo(
      @NotNull final BindingTrace trace,
      @Nullable final TraceEntryFilter filter,
      boolean commitDiagnostics,
      @NotNull MutableSlicedMap map,
      MutableDiagnosticsWithSuppression diagnostics) {
    map.forEach(
        new Function3<WritableSlice, Object, Object, Void>() {
          @Override
          public Void invoke(WritableSlice slice, Object key, Object value) {
            if (filter == null || filter.accept(slice, key)) {
              trace.record(slice, key, value);
            }

            return null;
          }
        });

    if (!commitDiagnostics) return;

    for (Diagnostic diagnostic : diagnostics.getOwnDiagnostics()) {
      if (filter == null || filter.accept(null, diagnostic.getPsiElement())) {
        trace.report(diagnostic);
      }
    }
  }
Пример #2
0
 @NotNull
 private static List<DiagnosticDescriptor> getSortedDiagnosticDescriptors(
     @NotNull Collection<Diagnostic> diagnostics) {
   LinkedListMultimap<TextRange, Diagnostic> diagnosticsGroupedByRanges =
       LinkedListMultimap.create();
   for (Diagnostic diagnostic : diagnostics) {
     if (!diagnostic.isValid()) continue;
     for (TextRange textRange : diagnostic.getTextRanges()) {
       diagnosticsGroupedByRanges.put(textRange, diagnostic);
     }
   }
   List<DiagnosticDescriptor> diagnosticDescriptors = Lists.newArrayList();
   for (TextRange range : diagnosticsGroupedByRanges.keySet()) {
     diagnosticDescriptors.add(
         new DiagnosticDescriptor(
             range.getStartOffset(), range.getEndOffset(), diagnosticsGroupedByRanges.get(range)));
   }
   Collections.sort(
       diagnosticDescriptors,
       new Comparator<DiagnosticDescriptor>() {
         @Override
         public int compare(@NotNull DiagnosticDescriptor d1, @NotNull DiagnosticDescriptor d2) {
           // Start early -- go first; start at the same offset, the one who end later is the
           // outer, i.e. goes first
           return (d1.start != d2.start) ? d1.start - d2.start : d2.end - d1.end;
         }
       });
   return diagnosticDescriptors;
 }
Пример #3
0
 private static void openDiagnosticsString(
     StringBuffer result,
     DiagnosticDescriptor currentDescriptor,
     Map<Diagnostic, TextDiagnostic> diagnosticToExpectedDiagnostic) {
   result.append("<!");
   for (Iterator<Diagnostic> iterator = currentDescriptor.diagnostics.iterator();
       iterator.hasNext(); ) {
     Diagnostic diagnostic = iterator.next();
     if (diagnosticToExpectedDiagnostic.containsKey(diagnostic)) {
       TextDiagnostic expectedDiagnostic = diagnosticToExpectedDiagnostic.get(diagnostic);
       TextDiagnostic actualTextDiagnostic = TextDiagnostic.asTextDiagnostic(diagnostic);
       if (compareTextDiagnostic(expectedDiagnostic, actualTextDiagnostic)) {
         result.append(expectedDiagnostic.asString());
       } else {
         result.append(actualTextDiagnostic.asString());
       }
     } else {
       result.append(diagnostic.getFactory().getName());
     }
     if (iterator.hasNext()) {
       result.append(", ");
     }
   }
   result.append("!>");
 }
Пример #4
0
 private static void assertSameFile(Collection<Diagnostic> actual) {
   if (actual.isEmpty()) return;
   PsiFile file = actual.iterator().next().getPsiElement().getContainingFile();
   for (Diagnostic diagnostic : actual) {
     assert diagnostic.getPsiFile().equals(file)
         : "All diagnostics should come from the same file: "
             + diagnostic.getPsiFile()
             + ", "
             + file;
   }
 }
Пример #5
0
 private static void unexpectedDiagnostics(
     List<Diagnostic> actual, DiagnosticDiffCallbacks callbacks) {
   for (Diagnostic diagnostic : actual) {
     List<TextRange> textRanges = diagnostic.getTextRanges();
     for (TextRange textRange : textRanges) {
       callbacks.unexpectedDiagnostic(
           TextDiagnostic.asTextDiagnostic(diagnostic),
           textRange.getStartOffset(),
           textRange.getEndOffset());
     }
   }
 }
Пример #6
0
 @Override
 public int compare(@NotNull Diagnostic o1, @NotNull Diagnostic o2) {
   List<TextRange> ranges1 = o1.getTextRanges();
   List<TextRange> ranges2 = o2.getTextRanges();
   int minNumberOfRanges = ranges1.size() < ranges2.size() ? ranges1.size() : ranges2.size();
   for (int i = 0; i < minNumberOfRanges; i++) {
     TextRange range1 = ranges1.get(i);
     TextRange range2 = ranges2.get(i);
     int startOffset1 = range1.getStartOffset();
     int startOffset2 = range2.getStartOffset();
     if (startOffset1 != startOffset2) {
       // Start early -- go first
       return startOffset1 - range2.getStartOffset();
     }
     int endOffset1 = range1.getEndOffset();
     int endOffset2 = range2.getEndOffset();
     if (endOffset1 != endOffset2) {
       // start at the same offset, the one who end later is the outer, i.e. goes first
       return endOffset2 - endOffset1;
     }
   }
   return ranges1.size() - ranges2.size();
 }
Пример #7
0
 @NotNull
 public static TextDiagnostic asTextDiagnostic(@NotNull Diagnostic diagnostic) {
   DiagnosticRenderer renderer = DefaultErrorMessages.getRendererForDiagnostic(diagnostic);
   String diagnosticName = diagnostic.getFactory().getName();
   if (renderer instanceof AbstractDiagnosticWithParametersRenderer) {
     //noinspection unchecked
     Object[] renderParameters =
         ((AbstractDiagnosticWithParametersRenderer) renderer).renderParameters(diagnostic);
     List<String> parameters =
         ContainerUtil.map(
             renderParameters,
             new Function<Object, String>() {
               @Override
               public String fun(Object o) {
                 return o != null ? o.toString() : "null";
               }
             });
     return new TextDiagnostic(diagnosticName, parameters);
   }
   return new TextDiagnostic(diagnosticName, null);
 }
  @NotNull
  @Override
  protected List<IntentionAction> doCreateActions(@NotNull Diagnostic diagnostic) {
    List<IntentionAction> actions = new LinkedList<IntentionAction>();

    BindingContext context = ResolutionUtils.analyzeFully((JetFile) diagnostic.getPsiFile());

    PsiElement diagnosticElement = diagnostic.getPsiElement();
    if (!(diagnosticElement instanceof JetExpression)) {
      LOG.error("Unexpected element: " + diagnosticElement.getText());
      return Collections.emptyList();
    }

    JetExpression expression = (JetExpression) diagnosticElement;

    JetType expectedType;
    JetType expressionType;
    if (diagnostic.getFactory() == Errors.TYPE_MISMATCH) {
      DiagnosticWithParameters2<JetExpression, JetType, JetType> diagnosticWithParameters =
          Errors.TYPE_MISMATCH.cast(diagnostic);
      expectedType = diagnosticWithParameters.getA();
      expressionType = diagnosticWithParameters.getB();
    } else if (diagnostic.getFactory() == Errors.NULL_FOR_NONNULL_TYPE) {
      DiagnosticWithParameters1<JetConstantExpression, JetType> diagnosticWithParameters =
          Errors.NULL_FOR_NONNULL_TYPE.cast(diagnostic);
      expectedType = diagnosticWithParameters.getA();
      expressionType = TypeUtilsKt.makeNullable(expectedType);
    } else if (diagnostic.getFactory() == Errors.CONSTANT_EXPECTED_TYPE_MISMATCH) {
      DiagnosticWithParameters2<JetConstantExpression, String, JetType> diagnosticWithParameters =
          Errors.CONSTANT_EXPECTED_TYPE_MISMATCH.cast(diagnostic);
      expectedType = diagnosticWithParameters.getB();
      expressionType = context.getType(expression);
      if (expressionType == null) {
        LOG.error("No type inferred: " + expression.getText());
        return Collections.emptyList();
      }
    } else {
      LOG.error("Unexpected diagnostic: " + DefaultErrorMessages.render(diagnostic));
      return Collections.emptyList();
    }

    // We don't want to cast a cast or type-asserted expression:
    if (!(expression instanceof JetBinaryExpressionWithTypeRHS)
        && !(expression.getParent() instanceof JetBinaryExpressionWithTypeRHS)) {
      actions.add(new CastExpressionFix(expression, expectedType));
    }

    // Property initializer type mismatch property type:
    JetProperty property = PsiTreeUtil.getParentOfType(expression, JetProperty.class);
    if (property != null) {
      JetPropertyAccessor getter = property.getGetter();
      JetExpression initializer = property.getInitializer();
      if (QuickFixUtil.canEvaluateTo(initializer, expression)
          || (getter != null
              && QuickFixUtil.canFunctionOrGetterReturnExpression(
                  property.getGetter(), expression))) {
        LexicalScope scope =
            CorePackage.getResolutionScope(
                property, context, ResolutionUtils.getResolutionFacade(property));
        JetType typeToInsert =
            TypeUtils.approximateWithResolvableType(expressionType, scope, false);
        actions.add(new ChangeVariableTypeFix(property, typeToInsert));
      }
    }

    PsiElement expressionParent = expression.getParent();

    // Mismatch in returned expression:

    JetCallableDeclaration function =
        expressionParent instanceof JetReturnExpression
            ? BindingContextUtilPackage.getTargetFunction(
                (JetReturnExpression) expressionParent, context)
            : PsiTreeUtil.getParentOfType(expression, JetFunction.class, true);
    if (function instanceof JetFunction
        && QuickFixUtil.canFunctionOrGetterReturnExpression(function, expression)) {
      LexicalScope scope =
          CorePackage.getResolutionScope(
              function, context, ResolutionUtils.getResolutionFacade(function));
      JetType typeToInsert = TypeUtils.approximateWithResolvableType(expressionType, scope, false);
      actions.add(new ChangeFunctionReturnTypeFix((JetFunction) function, typeToInsert));
    }

    // Fixing overloaded operators:
    if (expression instanceof JetOperationExpression) {
      ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, context);
      if (resolvedCall != null) {
        JetFunction declaration = getFunctionDeclaration(resolvedCall);
        if (declaration != null) {
          actions.add(new ChangeFunctionReturnTypeFix(declaration, expectedType));
        }
      }
    }

    // Change function return type when TYPE_MISMATCH is reported on call expression:
    if (expression instanceof JetCallExpression) {
      ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, context);
      if (resolvedCall != null) {
        JetFunction declaration = getFunctionDeclaration(resolvedCall);
        if (declaration != null) {
          actions.add(new ChangeFunctionReturnTypeFix(declaration, expectedType));
        }
      }
    }

    ResolvedCall<? extends CallableDescriptor> resolvedCall =
        CallUtilPackage.getParentResolvedCall(expression, context, true);
    if (resolvedCall != null) {
      // to fix 'type mismatch' on 'if' branches
      // todo: the same with 'when'
      JetExpression parentIf = QuickFixUtil.getParentIfForBranch(expression);
      JetExpression argumentExpression = (parentIf != null) ? parentIf : expression;
      ValueArgument valueArgument =
          CallUtilPackage.getValueArgumentForExpression(resolvedCall.getCall(), argumentExpression);
      if (valueArgument != null) {
        JetParameter correspondingParameter =
            QuickFixUtil.getParameterDeclarationForValueArgument(resolvedCall, valueArgument);
        JetType valueArgumentType =
            diagnostic.getFactory() == Errors.NULL_FOR_NONNULL_TYPE
                ? expressionType
                : context.getType(valueArgument.getArgumentExpression());
        if (correspondingParameter != null && valueArgumentType != null) {
          JetCallableDeclaration callable =
              PsiTreeUtil.getParentOfType(
                  correspondingParameter, JetCallableDeclaration.class, true);
          LexicalScope scope =
              callable != null
                  ? CorePackage.getResolutionScope(
                      callable, context, ResolutionUtils.getResolutionFacade(callable))
                  : null;
          JetType typeToInsert =
              TypeUtils.approximateWithResolvableType(valueArgumentType, scope, true);
          actions.add(new ChangeParameterTypeFix(correspondingParameter, typeToInsert));
        }
      }
    }
    return actions;
  }
Пример #9
0
 @Override
 public void report(@NotNull Diagnostic diagnostic) {
   if (diagnostic.getSeverity() == Severity.ERROR) {
     throw new IllegalStateException(DefaultErrorMessages.render(diagnostic));
   }
 }
Пример #10
0
 @Override
 public void report(@NotNull Diagnostic diagnostic) {
   if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(diagnostic.getFactory())) {
     throw new IllegalStateException("Unresolved: " + diagnostic.getPsiElement().getText());
   }
 }