diff options
author | Tor Norbye <tnorbye@google.com> | 2012-09-18 14:19:15 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2012-09-18 14:19:15 -0700 |
commit | 2e3527410003859ee6bcb3a2971d72bcfdbcc829 (patch) | |
tree | 62b70635e6e2bc8daa2318235bfe4966f6b3fa07 | |
parent | 6184f12fa097e1c5bddfe50700b3b0740c736a5a (diff) | |
download | sdk-2e3527410003859ee6bcb3a2971d72bcfdbcc829.zip sdk-2e3527410003859ee6bcb3a2971d72bcfdbcc829.tar.gz sdk-2e3527410003859ee6bcb3a2971d72bcfdbcc829.tar.bz2 |
Improvements to stacktrace handler for constructors
This changeset improves the SourceRevealer for certain types of
stacktraces:
(1) Constructors. If your class initializes fields using code, these
are logically grouped into the constructor, but the linenumbers do
not fit the constructor source range. Before this CL, this would
cause the revealer to show the constructor method rather than the
field initialization line.
(2) Class initializers. If you clicked on a class initializer method,
the IDE would throw an NPE. There's now some special handling to
deal with these.
Change-Id: Ibb3b7dcf13a69018f75fd12648d1f6b5c45625cc
3 files changed, 42 insertions, 4 deletions
diff --git a/common/src/com/android/SdkConstants.java b/common/src/com/android/SdkConstants.java index 1e1d14f..1aa3853 100644 --- a/common/src/com/android/SdkConstants.java +++ b/common/src/com/android/SdkConstants.java @@ -957,6 +957,7 @@ public final class SdkConstants { // Class Names public static final String CONSTRUCTOR_NAME = "<init>"; //$NON-NLS-1$ + public static final String CLASS_CONSTRUCTOR = "<clinit>"; //$NON-NLS-1$ public static final String FRAGMENT = "android/app/Fragment"; //$NON-NLS-1$ public static final String FRAGMENT_V4 = "android/support/v4/app/Fragment"; //$NON-NLS-1$ public static final String ANDROID_APP_ACTIVITY = "android/app/Activity"; //$NON-NLS-1$ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/SourceRevealer.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/SourceRevealer.java index 85f6992..b1b5390 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/SourceRevealer.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/SourceRevealer.java @@ -16,6 +16,7 @@ package com.android.ide.eclipse.adt; +import static com.android.SdkConstants.CLASS_CONSTRUCTOR; import static com.android.SdkConstants.CONSTRUCTOR_NAME; import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; @@ -31,8 +32,10 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.ISourceRange; +import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.search.IJavaSearchConstants; import org.eclipse.jdt.core.search.SearchEngine; @@ -138,9 +141,15 @@ public class SourceRevealer implements ISourceRevealer { // See if the line number looks like it's inside the given method ISourceRange sourceRange = method.getSourceRange(); IRegion region = AdtUtils.getRegionOfLine(file, lineNumber - 1); - if (region != null - && region.getOffset() >= sourceRange.getOffset() - && region.getOffset() < sourceRange.getOffset() + // When fields are initialized with code, this logically belongs + // to the constructor, but the line numbers are outside of the + // constructor. In this case we'll trust the line number rather + // than the method range. + boolean isConstructor = fqmn.endsWith(CONSTRUCTOR_NAME); + if (isConstructor + || region != null + && region.getOffset() >= sourceRange.getOffset() + && region.getOffset() < sourceRange.getOffset() + sourceRange.getLength()) { // Yes: use the line number instead if (perspective != null) { @@ -167,6 +176,29 @@ public class SourceRevealer implements ISourceRevealer { if (fileMatches.size() > 0) { return revealLineMatch(fileMatches, fileName, lineNumber, perspective); } else { + // Last ditch effort: attempt to look up the class corresponding to the fqn + // and jump to the line there + if (fileMatches.isEmpty() && fqmn.indexOf('.') != -1) { + String className = fqmn.substring(0, fqmn.lastIndexOf('.')); + for (IJavaProject project : BaseProjectHelper.getAndroidProjects(null)) { + IType type; + try { + type = project.findType(className); + if (type != null && type.exists()) { + IResource resource = type.getResource(); + if (resource instanceof IFile) { + if (perspective != null) { + SourceRevealer.switchToPerspective(perspective); + } + return displayFile((IFile) resource, lineNumber); + } + } + } catch (JavaModelException e) { + AdtPlugin.log(e, null); + } + } + } + return false; } } @@ -349,6 +381,11 @@ public class SourceRevealer implements ISourceRevealer { return searchForPattern(fqmn, IJavaSearchConstants.CONSTRUCTOR, MATCH_IS_METHOD_PREDICATE); } + if (fqmn.endsWith(CLASS_CONSTRUCTOR)) { + // Don't try to search for class init methods: Eclipse will throw NPEs if you do + return Collections.emptyList(); + } + return searchForPattern(fqmn, IJavaSearchConstants.METHOD, MATCH_IS_METHOD_PREDICATE); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java index ed93b73..55cad2b 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java @@ -409,7 +409,7 @@ public class ManifestInfo { * Returns the minimum SDK version name (which may not be a numeric string, e.g. * it could be a codename). It will never be null or empty; if no min sdk version * was specified in the manifest, the return value will be "1". Use - * {@link #getCodeName()} instead if you want to look up whether there is a code name. + * {@link #getMinSdkCodeName()} instead if you want to look up whether there is a code name. * * @return the minimum SDK version */ |