]> source.dussan.org Git - aspectj.git/blob
a6504a5fe8e11dfc4671b6d88f73f2f459c6b800
[aspectj.git] /
1 /* *******************************************************************
2  * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
3  * All rights reserved.
4  * This program and the accompanying materials are made available
5  * under the terms of the Eclipse Public License v 2.0
6  * which accompanies this distribution and is available at
7  * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
8  *
9  * Contributors:
10  *     PARC     initial implementation
11  * ******************************************************************/
12
13 package org.aspectj.ajdt.internal.compiler.problem;
14
15 import java.io.PrintWriter;
16 import java.io.StringWriter;
17 import java.lang.reflect.Modifier;
18 import java.util.Collection;
19 import java.util.HashSet;
20 import java.util.List;
21 import java.util.Set;
22
23 import org.aspectj.ajdt.internal.compiler.ast.AdviceDeclaration;
24 import org.aspectj.ajdt.internal.compiler.ast.AspectDeclaration;
25 import org.aspectj.ajdt.internal.compiler.ast.DeclareAnnotationDeclaration;
26 import org.aspectj.ajdt.internal.compiler.ast.IfMethodDeclaration;
27 import org.aspectj.ajdt.internal.compiler.ast.PointcutDeclaration;
28 import org.aspectj.ajdt.internal.compiler.ast.Proceed;
29 import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
30 import org.aspectj.ajdt.internal.compiler.lookup.InterTypeMethodBinding;
31 import org.aspectj.ajdt.internal.compiler.lookup.PrivilegedFieldBinding;
32 import org.aspectj.bridge.context.CompilationAndWeavingContext;
33 import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
34 import org.aspectj.org.eclipse.jdt.core.compiler.IProblem;
35 import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
36 import org.aspectj.org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
37 import org.aspectj.org.eclipse.jdt.internal.compiler.IProblemFactory;
38 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ASTNode;
39 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
40 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation;
41 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Argument;
42 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
43 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Expression;
44 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
45 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
46 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
47 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
48 import org.aspectj.org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
49 import org.aspectj.org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
50 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
51 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.IPrivilegedHandler;
52 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
53 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
54 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ParameterizedMethodBinding;
55 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
56 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Scope;
57 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
58 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TagBits;
59 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
60 import org.aspectj.org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
61 import org.aspectj.org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
62 import org.aspectj.util.FuzzyBoolean;
63 import org.aspectj.weaver.AjcMemberMaker;
64 import org.aspectj.weaver.ConcreteTypeMunger;
65 import org.aspectj.weaver.ReferenceType;
66 import org.aspectj.weaver.ResolvedMember;
67 import org.aspectj.weaver.ResolvedType;
68 import org.aspectj.weaver.ResolvedTypeMunger;
69 import org.aspectj.weaver.Shadow;
70 import org.aspectj.weaver.UnresolvedType;
71 import org.aspectj.weaver.patterns.Declare;
72 import org.aspectj.weaver.patterns.DeclareAnnotation;
73 import org.aspectj.weaver.patterns.DeclareParents;
74 import org.aspectj.weaver.patterns.DeclareSoft;
75 import org.aspectj.weaver.patterns.TypePattern;
76
77 /**
78  * Extends problem reporter to support compiler-side implementation of declare soft. Also overrides error reporting for the need to
79  * implement abstract methods to account for inter-type declarations and pointcut declarations. This second job might be better done
80  * directly in the SourceTypeBinding/ClassScope classes.
81  *
82  * @author Jim Hugunin
83  */
84 public class AjProblemReporter extends ProblemReporter {
85
86         private static final boolean DUMP_STACK = false;
87
88         public EclipseFactory factory;
89
90         public AjProblemReporter(IErrorHandlingPolicy policy, CompilerOptions options, IProblemFactory problemFactory) {
91                 super(policy, options, problemFactory);
92         }
93
94         public void unhandledException(TypeBinding exceptionType, ASTNode location) {
95                 if (!factory.getWorld().getDeclareSoft().isEmpty()) {
96                         Shadow callSite = factory.makeShadow(location, referenceContext);
97                         Shadow enclosingExec = factory.makeShadow(referenceContext);
98                         // PR 72157 - calls to super / this within a constructor are not part of the cons join point.
99                         if ((callSite == null) && (enclosingExec.getKind() == Shadow.ConstructorExecution)
100                                         && (location instanceof ExplicitConstructorCall)) {
101                                 super.unhandledException(exceptionType, location);
102                                 return;
103                         }
104                         // System.err.println("about to show error for unhandled exception: " + new String(exceptionType.sourceName()) +
105                         // " at " + location + " in " + referenceContext);
106
107                         for (DeclareSoft d: factory.getWorld().getDeclareSoft()) {
108 //                      for (Iterator<DeclareSoft> i = factory.getWorld().getDeclareSoft().iterator(); i.hasNext();) {
109 //                              DeclareSoft d = (DeclareSoft) i.next();
110                                 // We need the exceptionType to match the type in the declare soft statement
111                                 // This means it must either be the same type or a subtype
112                                 ResolvedType throwException = factory.fromEclipse((ReferenceBinding) exceptionType);
113                                 FuzzyBoolean isExceptionTypeOrSubtype = d.getException().matchesInstanceof(throwException);
114                                 if (!isExceptionTypeOrSubtype.alwaysTrue())
115                                         continue;
116
117                                 if (callSite != null) {
118                                         FuzzyBoolean match = d.getPointcut().match(callSite);
119                                         if (match.alwaysTrue()) {
120                                                 // System.err.println("matched callSite: " + callSite + " with " + d);
121                                                 return;
122                                         } else if (!match.alwaysFalse()) {
123                                                 // !!! need this check to happen much sooner
124                                                 // throw new RuntimeException("unimplemented, shouldn't have fuzzy match here");
125                                         }
126                                 }
127                                 if (enclosingExec != null) {
128                                         FuzzyBoolean match = d.getPointcut().match(enclosingExec);
129                                         if (match.alwaysTrue()) {
130                                                 // System.err.println("matched enclosingExec: " + enclosingExec + " with " + d);
131                                                 return;
132                                         } else if (!match.alwaysFalse()) {
133                                                 // !!! need this check to happen much sooner
134                                                 // throw new RuntimeException("unimplemented, shouldn't have fuzzy match here");
135                                         }
136                                 }
137                         }
138                 }
139
140                 // ??? is this always correct
141                 if (location instanceof Proceed) {
142                         return;
143                 }
144
145                 super.unhandledException(exceptionType, location);
146         }
147
148         public void unhandledExceptionFromAutoClose(TypeBinding exceptionType, ASTNode location) {
149                 if (!factory.getWorld().getDeclareSoft().isEmpty()) {
150                         Shadow callSite = factory.makeShadow(location, referenceContext);
151                         Shadow enclosingExec = factory.makeShadow(referenceContext);
152                         // PR 72157 - calls to super / this within a constructor are not part of the cons join point.
153                         if ((callSite == null) && (enclosingExec.getKind() == Shadow.ConstructorExecution)
154                                         && (location instanceof ExplicitConstructorCall)) {
155                                 super.unhandledException(exceptionType, location);
156                                 return;
157                         }
158                         // System.err.println("about to show error for unhandled exception: " + new String(exceptionType.sourceName()) +
159                         // " at " + location + " in " + referenceContext);
160
161                         for (DeclareSoft d: factory.getWorld().getDeclareSoft()) {
162 //                      for (Iterator<DeclareSoft> i = factory.getWorld().getDeclareSoft().iterator(); i.hasNext();) {
163 //                              DeclareSoft d = (DeclareSoft) i.next();
164                                 // We need the exceptionType to match the type in the declare soft statement
165                                 // This means it must either be the same type or a subtype
166                                 ResolvedType throwException = factory.fromEclipse((ReferenceBinding) exceptionType);
167                                 FuzzyBoolean isExceptionTypeOrSubtype = d.getException().matchesInstanceof(throwException);
168                                 if (!isExceptionTypeOrSubtype.alwaysTrue())
169                                         continue;
170
171                                 if (callSite != null) {
172                                         FuzzyBoolean match = d.getPointcut().match(callSite);
173                                         if (match.alwaysTrue()) {
174                                                 // System.err.println("matched callSite: " + callSite + " with " + d);
175                                                 return;
176                                         } else if (!match.alwaysFalse()) {
177                                                 // !!! need this check to happen much sooner
178                                                 // throw new RuntimeException("unimplemented, shouldn't have fuzzy match here");
179                                         }
180                                 }
181                                 if (enclosingExec != null) {
182                                         FuzzyBoolean match = d.getPointcut().match(enclosingExec);
183                                         if (match.alwaysTrue()) {
184                                                 // System.err.println("matched enclosingExec: " + enclosingExec + " with " + d);
185                                                 return;
186                                         } else if (!match.alwaysFalse()) {
187                                                 // !!! need this check to happen much sooner
188                                                 // throw new RuntimeException("unimplemented, shouldn't have fuzzy match here");
189                                         }
190                                 }
191                         }
192                 }
193
194                 // ??? is this always correct
195                 if (location instanceof Proceed) {
196                         return;
197                 }
198
199                 super.unhandledExceptionFromAutoClose(exceptionType, location);
200         }
201
202         private boolean isPointcutDeclaration(MethodBinding binding) {
203                 return CharOperation.prefixEquals(PointcutDeclaration.mangledPrefix, binding.selector);
204         }
205
206         private boolean isIntertypeDeclaration(MethodBinding binding) {
207                 return (binding instanceof InterTypeMethodBinding);
208         }
209
210         public void abstractMethodCannotBeOverridden(SourceTypeBinding type, MethodBinding concreteMethod) {
211                 if (isPointcutDeclaration(concreteMethod)) {
212                         return;
213                 }
214                 super.abstractMethodCannotBeOverridden(type, concreteMethod);
215         }
216
217         public void inheritedMethodReducesVisibility(SourceTypeBinding type, MethodBinding concreteMethod,
218                         MethodBinding[] abstractMethods) {
219                 // if we implemented this method by a public inter-type declaration, then there is no error
220
221                 ResolvedType onTypeX = null;
222                 // If the type is anonymous, look at its supertype
223                 if (!type.isAnonymousType()) {
224                         onTypeX = factory.fromEclipse(type);
225                 } else {
226                         // Hmmm. If the ITD is on an interface that is being 'instantiated' using an anonymous type,
227                         // we sort it out elsewhere and don't come into this method -
228                         // so we don't have to worry about interfaces, just the superclass.
229                         onTypeX = factory.fromEclipse(type.superclass()); // abstractMethod.declaringClass);
230                 }
231                 for (ConcreteTypeMunger m : onTypeX.getInterTypeMungersIncludingSupers()) {
232                         ResolvedMember sig = m.getSignature();
233                         if (!Modifier.isAbstract(sig.getModifiers())) {
234                                 if (ResolvedType.matches(
235                                                 AjcMemberMaker.interMethod(sig, m.getAspectType(), sig.getDeclaringType().resolve(factory.getWorld())
236                                                                 .isInterface()), factory.makeResolvedMember(concreteMethod))) {
237                                         return;
238                                 }
239                         }
240                 }
241
242                 super.inheritedMethodReducesVisibility(type, concreteMethod, abstractMethods);
243         }
244
245         // if either of the MethodBinding is an ITD, we have already reported it.
246         public void staticAndInstanceConflict(MethodBinding currentMethod, MethodBinding inheritedMethod) {
247                 if (currentMethod instanceof InterTypeMethodBinding)
248                         return;
249                 if (inheritedMethod instanceof InterTypeMethodBinding)
250                         return;
251                 super.staticAndInstanceConflict(currentMethod, inheritedMethod);
252         }
253
254         public void abstractMethodMustBeImplemented(SourceTypeBinding type, MethodBinding abstractMethod) {
255                 // if this is a PointcutDeclaration then there is no error
256                 if (isPointcutDeclaration(abstractMethod))
257                         return;
258
259                 if (isIntertypeDeclaration(abstractMethod))
260                         return; // when there is a problem with an ITD not being implemented, it will be reported elsewhere
261
262                 if (CharOperation.prefixEquals("ajc$interField".toCharArray(), abstractMethod.selector)) {
263                         // ??? think through how this could go wrong
264                         return;
265                 }
266
267                 // if we implemented this method by an inter-type declaration, then there is no error
268                 // ??? be sure this is always right
269                 ResolvedType onTypeX = null;
270
271                 // If the type is anonymous, look at its supertype
272                 if (!type.isAnonymousType()) {
273                         onTypeX = factory.fromEclipse(type);
274                 } else {
275                         // Hmmm. If the ITD is on an interface that is being 'instantiated' using an anonymous type,
276                         // we sort it out elsewhere and don't come into this method -
277                         // so we don't have to worry about interfaces, just the superclass.
278                         onTypeX = factory.fromEclipse(type.superclass()); // abstractMethod.declaringClass);
279                 }
280
281                 if (onTypeX.isRawType())
282                         onTypeX = onTypeX.getGenericType();
283
284                 List<ConcreteTypeMunger> mungers = onTypeX.getInterTypeMungersIncludingSupers();
285                 for (ConcreteTypeMunger m : mungers) {
286                         ResolvedMember sig = m.getSignature();
287                         if (sig != null && !Modifier.isAbstract(sig.getModifiers())) {
288                                 ResolvedMember abstractMember = factory.makeResolvedMember(abstractMethod);
289                                 if (abstractMember.getName().startsWith("ajc$interMethodDispatch")) {
290                                         ResolvedType dType = factory.getWorld().resolve(sig.getDeclaringType(), false);
291                                         if (ResolvedType.matches(AjcMemberMaker.interMethod(sig, m.getAspectType(), dType.isInterface()),
292                                                         abstractMember)) {
293                                                 return;
294                                         }
295                                 } else {
296                                         // In this case we have something like:
297                                         // interface I {}
298                                         // abstract class C implements I { abstract void foo();}
299                                         // class D extends C {}
300                                         // ITD: public void I.foo() {...}
301                                         // The ITD is providing the implementation of foo in the class D but when checking for whether the abstract
302                                         // method is overridden, we won't be looking at whether the ITD overrides ajc$interMethodDispath$...foo but
303                                         // whether it overrides the foo method from class C
304                                         if (ResolvedType.matches(sig, factory.makeResolvedMember(abstractMethod)))
305                                                 return;
306                                 }
307                         }
308                 }
309
310                 super.abstractMethodMustBeImplemented(type, abstractMethod);
311         }
312
313         /*
314          * (non-Javadoc)
315          *
316          * @see
317          * org.aspectj.org.eclipse.jdt.internal.compiler.problem.ProblemReporter#disallowedTargetForAnnotation(org.aspectj.org.eclipse
318          * .jdt.internal.compiler.ast.Annotation)
319          */
320         public void disallowedTargetForAnnotation(Annotation annotation) {
321                 // if the annotation's recipient is an ITD, it might be allowed after all...
322                 if (annotation.recipient instanceof MethodBinding) {
323                         MethodBinding binding = (MethodBinding) annotation.recipient;
324                         String name = new String(binding.selector);
325                         if (name.startsWith("ajc$")) {
326                                 long metaTagBits = annotation.resolvedType.getAnnotationTagBits(); // could be forward reference
327                                 if (name.contains("interField")) {
328                                         if ((metaTagBits & TagBits.AnnotationForField) != 0)
329                                                 return;
330                                 } else if (name.contains("interConstructor")) {
331                                         if ((metaTagBits & TagBits.AnnotationForConstructor) != 0)
332                                                 return;
333                                 } else if (name.contains("interMethod")) {
334                                         if ((metaTagBits & TagBits.AnnotationForMethod) != 0)
335                                                 return;
336                                 } else if (name.contains("declare_" + DeclareAnnotation.AT_TYPE + "_")) {
337                                         if ((metaTagBits & TagBits.AnnotationForAnnotationType) != 0 || (metaTagBits & TagBits.AnnotationForType) != 0)
338                                                 return;
339                                 } else if (name.contains("declare_" + DeclareAnnotation.AT_FIELD + "_")) {
340                                         if ((metaTagBits & TagBits.AnnotationForField) != 0)
341                                                 return;
342                                 } else if (name.contains("declare_" + DeclareAnnotation.AT_CONSTRUCTOR + "_")) {
343                                         if ((metaTagBits & TagBits.AnnotationForConstructor) != 0)
344                                                 return;
345                                 } else if (name.contains("declare_eow")) {
346                                         if ((metaTagBits & TagBits.AnnotationForField) != 0)
347                                                 return;
348                                 }
349                         }
350                 }
351
352                 // not our special case, report the problem...
353                 super.disallowedTargetForAnnotation(annotation);
354         }
355
356         public void overridesPackageDefaultMethod(MethodBinding localMethod, MethodBinding inheritedMethod) {
357                 if (new String(localMethod.selector).startsWith("ajc$"))
358                         return;
359                 super.overridesPackageDefaultMethod(localMethod, inheritedMethod);
360         }
361
362         public void handle(int problemId, String[] problemArguments, String[] messageArguments, int severity, int problemStartPosition,
363                         int problemEndPosition, ReferenceContext referenceContext, CompilationResult unitResult) {
364                 if (severity != ProblemSeverities.Ignore && DUMP_STACK) {
365                         Thread.dumpStack();
366                 }
367                 super.handle(problemId, problemArguments,
368                                 0, // no message elaboration
369                                 messageArguments, severity, problemStartPosition, problemEndPosition,
370                                 referenceContext, unitResult);
371         }
372
373         // PR71076
374         public void javadocMissingParamTag(char[] name, int sourceStart, int sourceEnd, int modifiers) {
375                 boolean reportIt = true;
376                 String sName = new String(name);
377                 if (sName.startsWith("ajc$"))
378                         reportIt = false;
379                 if (sName.equals("thisJoinPoint"))
380                         reportIt = false;
381                 if (sName.equals("thisJoinPointStaticPart"))
382                         reportIt = false;
383                 if (sName.equals("thisEnclosingJoinPointStaticPart"))
384                         reportIt = false;
385                 if (sName.equals("ajc_aroundClosure"))
386                         reportIt = false;
387                 if (reportIt)
388                         super.javadocMissingParamTag(name, sourceStart, sourceEnd, modifiers);
389         }
390
391         public void abstractMethodInAbstractClass(SourceTypeBinding type, AbstractMethodDeclaration methodDecl) {
392
393                 String abstractMethodName = new String(methodDecl.selector);
394                 if (abstractMethodName.startsWith("ajc$pointcut")) {
395                         // This will already have been reported, see: PointcutDeclaration.postParse()
396                         return;
397                 }
398                 String[] arguments = new String[] { new String(type.sourceName()), abstractMethodName };
399                 super.handle(IProblem.AbstractMethodInAbstractClass, arguments, arguments, methodDecl.sourceStart, methodDecl.sourceEnd,
400                                 this.referenceContext, this.referenceContext == null ? null : this.referenceContext.compilationResult());
401         }
402
403         /**
404          * Called when there is an ITD marked @override that doesn't override a supertypes method. The method and the binding are passed
405          * - some information is useful from each. The 'method' knows about source offsets for the message, the 'binding' has the
406          * signature of what the ITD is trying to be in the target class.
407          */
408         public void itdMethodMustOverride(AbstractMethodDeclaration method, MethodBinding binding) {
409                 this.handle(IProblem.MethodMustOverride,
410                                 new String[] { new String(binding.selector), typesAsString(binding.isVarargs(), binding.parameters, false),
411                                                 new String(binding.declaringClass.readableName()), },
412                                 new String[] { new String(binding.selector), typesAsString(binding.isVarargs(), binding.parameters, true),
413                                                 new String(binding.declaringClass.shortReadableName()), }, method.sourceStart, method.sourceEnd,
414                                 this.referenceContext, this.referenceContext == null ? null : this.referenceContext.compilationResult());
415         }
416
417         /**
418          * Overrides the implementation in ProblemReporter and is ITD aware. To report a *real* problem with an ITD marked @override,
419          * the other methodMustOverride() method is used.
420          */
421         public void methodMustOverride(AbstractMethodDeclaration method, long complianceLevel) {
422
423                 // ignore ajc$ methods
424                 if (new String(method.selector).startsWith("ajc$"))
425                         return;
426                 ResolvedMember possiblyErroneousRm = factory.makeResolvedMember(method.binding);
427
428                 ResolvedType onTypeX = factory.fromEclipse(method.binding.declaringClass);
429                 // Can't use 'getInterTypeMungersIncludingSupers()' since that will exclude abstract ITDs
430                 // on any super classes - so we have to trawl up ourselves.. I wonder if this problem
431                 // affects other code in the problem reporter that looks through ITDs...
432                 ResolvedType supertypeToLookAt = onTypeX.getSuperclass();
433                 while (supertypeToLookAt != null) {
434                         List<ConcreteTypeMunger> itMungers = supertypeToLookAt.getInterTypeMungers();
435                         for (ConcreteTypeMunger m : itMungers) {
436                                 if (m.getMunger() != null && m.getMunger().getKind() == ResolvedTypeMunger.PrivilegedAccess) {
437                                         continue;
438                                 }
439                                 ResolvedMember sig = m.getSignature();
440                                 if (sig == null)
441                                         continue; // we aren't interested in other kinds of munger
442                                 UnresolvedType dType = sig.getDeclaringType();
443                                 if (dType == null)
444                                         continue;
445                                 ResolvedType resolvedDeclaringType = dType.resolve(factory.getWorld());
446                                 ResolvedMember rm = AjcMemberMaker.interMethod(sig, m.getAspectType(), resolvedDeclaringType.isInterface());
447                                 if (ResolvedType.matches(rm, possiblyErroneousRm)) {
448                                         // match, so dont need to report a problem!
449                                         return;
450                                 }
451                         }
452                         supertypeToLookAt = supertypeToLookAt.getSuperclass();
453                 }
454                 // report the error...
455                 super.methodMustOverride(method,complianceLevel);
456         }
457
458         private String typesAsString(boolean isVarargs, TypeBinding[] types, boolean makeShort) {
459                 StringBuilder buffer = new StringBuilder(10);
460                 for (int i = 0, length = types.length; i < length; i++) {
461                         if (i != 0)
462                                 buffer.append(", "); //$NON-NLS-1$
463                         TypeBinding type = types[i];
464                         boolean isVarargType = isVarargs && i == length - 1;
465                         if (isVarargType)
466                                 type = ((ArrayBinding) type).elementsType();
467                         buffer.append(new String(makeShort ? type.shortReadableName() : type.readableName()));
468                         if (isVarargType)
469                                 buffer.append("..."); //$NON-NLS-1$
470                 }
471                 return buffer.toString();
472         }
473
474         public void visibilityConflict(MethodBinding currentMethod, MethodBinding inheritedMethod) {
475                 // Not quite sure if the conditions on this test are right - basically I'm saying
476                 // DONT WORRY if its ITDs since the error will be reported another way...
477                 if (isIntertypeDeclaration(currentMethod) && isIntertypeDeclaration(inheritedMethod)
478                                 && Modifier.isPrivate(currentMethod.modifiers) && Modifier.isPrivate(inheritedMethod.modifiers)) {
479                         return;
480                 }
481                 super.visibilityConflict(currentMethod, inheritedMethod);
482         }
483
484         public void unusedPrivateType(TypeDeclaration typeDecl) {
485                 // don't output unused type warnings for aspects!
486                 if (typeDecl instanceof AspectDeclaration)
487                         return;
488                 if (typeDecl.enclosingType != null && (typeDecl.enclosingType instanceof AspectDeclaration)) {
489                         AspectDeclaration ad = (AspectDeclaration) typeDecl.enclosingType;
490                         if (ad.concreteName != null) {
491                                 List<Declare> declares = ad.concreteName.declares;
492                                 for (Object dec : declares) {
493                                         if (dec instanceof DeclareParents) {
494                                                 DeclareParents decp = (DeclareParents) dec;
495                                                 TypePattern[] newparents = decp.getParents().getTypePatterns();
496                                                 for (TypePattern pattern : newparents) {
497                                                         UnresolvedType ut = pattern.getExactType();
498                                                         if (ut == null)
499                                                                 continue;
500                                                         if (CharOperation.compareWith(typeDecl.binding.signature(), ut.getSignature().toCharArray()) == 0)
501                                                                 return;
502                                                 }
503                                         }
504                                 }
505                         }
506                 }
507                 super.unusedPrivateType(typeDecl);
508         }
509
510         private final static char[] thisJoinPointName = "thisJoinPoint".toCharArray();
511         private final static char[] thisJoinPointStaticPartName = "thisJoinPointStaticPart".toCharArray();
512         private final static char[] thisEnclosingJoinPointStaticPartName = "thisEnclosingJoinPointStaticPart".toCharArray();
513         private final static char[] thisAspectInstanceName = "thisAspectInstance".toCharArray();
514
515         @Override
516         public void uninitializedLocalVariable(LocalVariableBinding binding, ASTNode location, Scope scope) {
517                 if (CharOperation.equals(binding.name, thisJoinPointName) ||
518                         CharOperation.equals(binding.name, thisJoinPointStaticPartName) ||
519                         CharOperation.equals(binding.name, thisAspectInstanceName) ||
520                         CharOperation.equals(binding.name, thisEnclosingJoinPointStaticPartName)) {
521                         // If in advice, this is not a problem
522                         if (binding.declaringScope!=null && (binding.declaringScope.referenceContext() instanceof AdviceDeclaration ||
523                                                                                                  binding.declaringScope.referenceContext() instanceof IfMethodDeclaration)) {
524                                 return;
525                         }
526                 }
527                 super.uninitializedLocalVariable(binding, location, scope);
528         }
529
530         public void abstractMethodInConcreteClass(SourceTypeBinding type) {
531                 if (type.scope!=null && type.scope.referenceContext instanceof AspectDeclaration) {
532                         // TODO could put out an Aspect specific message here
533                         return;
534                 }
535                 super.abstractMethodInConcreteClass(type);
536         }
537
538         // Don't warn if there is an ITD method/ctor from a privileged aspect
539         public void unusedPrivateField(FieldDeclaration fieldDecl) {
540                 if (fieldDecl!=null && fieldDecl.binding != null && fieldDecl.binding.declaringClass != null) {
541                         ReferenceBinding type = fieldDecl.binding.declaringClass;
542
543                         ResolvedType weaverType = null;
544                         if (!type.isAnonymousType()) {
545                                 weaverType = factory.fromEclipse(type);
546                         } else {
547                                 weaverType = factory.fromEclipse(type.superclass());
548                         }
549                         Set checked = new HashSet();
550                         for (ConcreteTypeMunger m : weaverType.getInterTypeMungersIncludingSupers()) {
551                                 ResolvedType theAspect = m.getAspectType();
552                                 if (!checked.contains(theAspect)) {
553                                         TypeBinding tb = factory.makeTypeBinding(m.getAspectType());
554                                         // Let's check the privilegedHandler from that aspect
555                                         if (tb instanceof SourceTypeBinding) { // BinaryTypeBinding is also a SourceTypeBinding ;)
556                                                 IPrivilegedHandler privilegedHandler = ((SourceTypeBinding) tb).privilegedHandler;
557                                                 if (privilegedHandler != null) {
558                                                         if (privilegedHandler.definesPrivilegedAccessToField(fieldDecl.binding)) {
559                                                                 return;
560                                                         }
561                                                 } else if (theAspect instanceof ReferenceType) {
562                                                         // ResolvedMember rm = factory.makeResolvedMember(fieldDecl.binding);
563                                                         String fname = new String(fieldDecl.name);
564                                                         Collection/* ResolvedMember */privvies = ((ReferenceType) theAspect).getPrivilegedAccesses();
565                                                         // On an incremental compile the information is in the bcel delegate
566                                                         if (privvies != null) {
567                                                                 for (Object privvy : privvies) {
568                                                                         ResolvedMember priv = (ResolvedMember) privvy;
569                                                                         if (priv.getName().equals(fname)) {
570                                                                                 return;
571                                                                         }
572                                                                 }
573                                                         }
574                                                 }
575                                         }
576                                         checked.add(theAspect);
577                                 }
578                         }
579                 }
580                 super.unusedPrivateField(fieldDecl);
581         }
582
583         public void unusedPrivateMethod(AbstractMethodDeclaration methodDecl) {
584                 // don't output unused warnings for pointcuts...
585                 if (!(methodDecl instanceof PointcutDeclaration))
586                         super.unusedPrivateMethod(methodDecl);
587         }
588
589         public void caseExpressionMustBeConstant(Expression expression) {
590                 if (expression instanceof QualifiedNameReference) {
591                         QualifiedNameReference qnr = (QualifiedNameReference) expression;
592                         if (qnr.otherBindings != null && qnr.otherBindings.length > 0 && qnr.otherBindings[0] instanceof PrivilegedFieldBinding) {
593                                 super.signalError(expression.sourceStart, expression.sourceEnd,
594                                                 "Fields accessible due to an aspect being privileged can not be used in switch statements");
595                                 referenceContext.tagAsHavingErrors();
596                                 return;
597                         }
598                 }
599                 super.caseExpressionMustBeConstant(expression);
600         }
601
602         public void unusedArgument(LocalDeclaration localDecl) {
603                 // don't warn if this is an aj synthetic arg
604                 String argType = new String(localDecl.type.resolvedType.signature());
605                 if (argType.startsWith("Lorg/aspectj/runtime/internal"))
606                         return;
607
608                 // If the unused argument is in a pointcut, don't report the problem (for now... pr148219)
609                 if (localDecl instanceof Argument) {
610                         Argument arg = (Argument) localDecl;
611                         if (arg.binding != null && arg.binding.declaringScope != null) {
612                                 ReferenceContext context = arg.binding.declaringScope.referenceContext();
613                                 if (context != null && context instanceof PointcutDeclaration)
614                                         return;
615                         }
616                 }
617                 if (new String(localDecl.name).startsWith("ajc$")) {
618                         // Do not report problems for infrastructure variables beyond the users control - pr195090
619                         return;
620                 }
621                 super.unusedArgument(localDecl);
622         }
623
624         /**
625          * A side-effect of the way that we handle itds on default methods on top-most implementors of interfaces is that a class
626          * acquiring a final default ITD will erroneously report that it can't override its own member. This method detects that
627          * situation.
628          */
629         public void finalMethodCannotBeOverridden(MethodBinding currentMethod, MethodBinding inheritedMethod) {
630                 if (currentMethod == inheritedMethod)
631                         return;
632                 super.finalMethodCannotBeOverridden(currentMethod, inheritedMethod);
633         }
634
635         /**
636          * The method verifier is a bit 'keen' and doesn't cope well with ITDMs which are of course to be considered a 'default'
637          * implementation if the target type doesn't supply one. This test may not be complete - it is possible that it should read if
638          * *either* is an ITD...but I dont have a testcase that shows that is required. yet. (pr115788)
639          */
640         public void duplicateInheritedMethods(SourceTypeBinding type, MethodBinding inheritedMethod1, MethodBinding inheritedMethod2, boolean isJava8) {
641                 if (inheritedMethod1 instanceof InterTypeMethodBinding || inheritedMethod2 instanceof InterTypeMethodBinding)
642                         return;
643                 if ((inheritedMethod1 instanceof ParameterizedMethodBinding)
644                                 && ((ParameterizedMethodBinding) inheritedMethod1).original() instanceof InterTypeMethodBinding)
645                         return;
646                 if ((inheritedMethod2 instanceof ParameterizedMethodBinding)
647                                 && ((ParameterizedMethodBinding) inheritedMethod2).original() instanceof InterTypeMethodBinding)
648                         return;
649                 super.duplicateInheritedMethods(type, inheritedMethod1, inheritedMethod2, isJava8);
650         }
651
652         /**
653          * All problems end up routed through here at some point...
654          */
655         public IProblem createProblem(char[] fileName, int problemId, String[] problemArguments, String[] messageArguments,
656                         int severity, int problemStartPosition, int problemEndPosition, int lineNumber) {
657                 IProblem problem = super.createProblem(fileName, problemId, problemArguments, messageArguments, severity,
658                                 problemStartPosition, problemEndPosition, lineNumber, 0);
659                 if (factory.getWorld().isInPinpointMode()) {
660                         MessageIssued ex = new MessageIssued();
661                         ex.fillInStackTrace();
662                         StringWriter sw = new StringWriter();
663                         ex.printStackTrace(new PrintWriter(sw));
664                         StringBuilder sb = new StringBuilder();
665                         sb.append(CompilationAndWeavingContext.getCurrentContext());
666                         sb.append(sw.toString());
667                         problem = new PinpointedProblem(problem, sb.toString());
668                 }
669                 return problem;
670         }
671
672         private static class MessageIssued extends RuntimeException {
673                 public String getMessage() {
674                         return "message issued...";
675                 }
676         }
677
678         private static class PinpointedProblem implements IProblem {
679
680                 private IProblem delegate;
681                 private String message;
682
683                 public PinpointedProblem(IProblem aProblem, String pinpoint) {
684                         this.delegate = aProblem;
685                         // if this was a problem that came via the weaver, it will already have
686                         // pinpoint info, don't do it twice...
687                         if (!delegate.getMessage().contains("message issued...")) {
688                                 this.message = delegate.getMessage() + "\n" + pinpoint;
689                         } else {
690                                 this.message = delegate.getMessage();
691                         }
692                 }
693
694                 public String[] getArguments() {
695                         return delegate.getArguments();
696                 }
697
698                 public int getID() {
699                         return delegate.getID();
700                 }
701
702                 public String getMessage() {
703                         return message;
704                 }
705
706                 public char[] getOriginatingFileName() {
707                         return delegate.getOriginatingFileName();
708                 }
709
710                 public int getSourceEnd() {
711                         return delegate.getSourceEnd();
712                 }
713
714                 public int getSourceLineNumber() {
715                         return delegate.getSourceLineNumber();
716                 }
717
718                 public int getSourceStart() {
719                         return delegate.getSourceStart();
720                 }
721
722                 public boolean isError() {
723                         return delegate.isError();
724                 }
725
726                 public boolean isWarning() {
727                         return delegate.isWarning();
728                 }
729
730                 public void setSourceEnd(int sourceEnd) {
731                         delegate.setSourceEnd(sourceEnd);
732                 }
733
734                 public void setSourceLineNumber(int lineNumber) {
735                         delegate.setSourceLineNumber(lineNumber);
736                 }
737
738                 public void setSourceStart(int sourceStart) {
739                         delegate.setSourceStart(sourceStart);
740                 }
741
742                 public void setSeeAlsoProblems(IProblem[] problems) {
743                         delegate.setSeeAlsoProblems(problems);
744                 }
745
746                 public IProblem[] seeAlso() {
747                         return delegate.seeAlso();
748                 }
749
750                 public void setSupplementaryMessageInfo(String msg) {
751                         delegate.setSupplementaryMessageInfo(msg);
752                 }
753
754                 public String getSupplementaryMessageInfo() {
755                         return delegate.getSupplementaryMessageInfo();
756                 }
757
758                 @Override
759                 public boolean isInfo() {
760                         return delegate.isInfo();
761                 }
762         }
763
764         public void duplicateMethodInType(AbstractMethodDeclaration methodDecl, boolean equalParameters, int severity) {
765                 if (new String(methodDecl.selector).startsWith("ajc$interMethod")) {
766                         // this is an ITD clash and will be reported in another way by AspectJ (173602)
767                         return;
768                 }
769                 super.duplicateMethodInType(methodDecl, equalParameters, severity);
770         }
771
772         // pr246393 - if we are going to complain about privileged, we clearly don't know what is going on, so don't
773         // confuse the user
774         public void parseErrorInsertAfterToken(int start, int end, int currentKind, char[] errorTokenSource, String errorTokenName,
775                         String expectedToken) {
776                 if (expectedToken.equals("privileged") || expectedToken.equals("around")) {
777                         super.parseErrorNoSuggestion(start, end, currentKind, errorTokenSource, errorTokenName);
778                 } else {
779                         super.parseErrorInsertAfterToken(start, end, currentKind, errorTokenSource, errorTokenName, expectedToken);
780                 }
781         }
782
783         public void missingValueForAnnotationMember(Annotation annotation, char[] memberName) {
784                 if (referenceContext instanceof DeclareAnnotationDeclaration) {
785                         // If a remover then the values are not necessary
786                         if (((DeclareAnnotationDeclaration) referenceContext).isRemover()) {
787                                 return;
788                         }
789                 }
790                 super.missingValueForAnnotationMember(annotation, memberName);
791         }
792
793 }