Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10)

Unified Diff: editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/internal/corext/refactoring/rename/RenameTypeMemberProcessor.java

Issue 10162026: Report warnings and non-fatal errors for shadowing declaration and usage. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Tweaks for review comments Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/internal/corext/refactoring/rename/RenameTypeMemberProcessor.java
diff --git a/editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/internal/corext/refactoring/rename/RenameTypeMemberProcessor.java b/editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/internal/corext/refactoring/rename/RenameTypeMemberProcessor.java
new file mode 100644
index 0000000000000000000000000000000000000000..d52bd97378815fadffd52e62d99aa9602cc38d65
--- /dev/null
+++ b/editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/internal/corext/refactoring/rename/RenameTypeMemberProcessor.java
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2012, the Dart project authors.
+ *
+ * Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html
+ *
+ * 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.google.dart.tools.internal.corext.refactoring.rename;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import com.google.dart.tools.core.internal.util.SourceRangeUtils;
+import com.google.dart.tools.core.model.CompilationUnit;
+import com.google.dart.tools.core.model.CompilationUnitElement;
+import com.google.dart.tools.core.model.DartLibrary;
+import com.google.dart.tools.core.model.DartModelException;
+import com.google.dart.tools.core.model.DartVariableDeclaration;
+import com.google.dart.tools.core.model.Method;
+import com.google.dart.tools.core.model.SourceRange;
+import com.google.dart.tools.core.model.Type;
+import com.google.dart.tools.core.model.TypeMember;
+import com.google.dart.tools.core.search.SearchMatch;
+import com.google.dart.tools.internal.corext.refactoring.Checks;
+import com.google.dart.tools.internal.corext.refactoring.RefactoringCoreMessages;
+import com.google.dart.tools.internal.corext.refactoring.base.DartStatusContext;
+import com.google.dart.tools.internal.corext.refactoring.changes.TextChangeCompatibility;
+import com.google.dart.tools.internal.corext.refactoring.util.Messages;
+import com.google.dart.tools.internal.corext.refactoring.util.TextChangeManager;
+import com.google.dart.tools.ui.internal.refactoring.RefactoringSaveHelper;
+import com.google.dart.tools.ui.internal.viewsupport.BasicElementLabels;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.ltk.core.refactoring.Change;
+import org.eclipse.ltk.core.refactoring.CompositeChange;
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+import org.eclipse.ltk.core.refactoring.TextChange;
+import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
+import org.eclipse.text.edits.ReplaceEdit;
+import org.eclipse.text.edits.TextEdit;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * {@link DartRenameProcessor} for {@link TypeMember}.
+ *
+ * @coverage dart.editor.ui.refactoring.core
+ */
+public abstract class RenameTypeMemberProcessor extends DartRenameProcessor {
+
+ private static void addTextEdit(TextChange change, String groupName, TextEdit textEdit) {
+ TextChangeCompatibility.addTextEdit(change, groupName, textEdit);
+ }
+
+ protected final TypeMember member;
+ private final String oldName;
+ private final TextChangeManager changeManager = new TextChangeManager(true);
+
+ private List<SearchMatch> references;
+
+ /**
+ * @param member the {@link TypeMember} to rename, not <code>null</code>.
+ */
+ public RenameTypeMemberProcessor(TypeMember member) {
+ this.member = member;
+ oldName = member.getElementName();
+ setNewElementName(oldName);
+ }
+
+ @Override
+ public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
+ return Checks.checkIfCuBroken(member);
+ }
+
+ @Override
+ public RefactoringStatus checkNewElementName(String newName) throws CoreException {
+ RefactoringStatus result = new RefactoringStatus();
+
+ if (Checks.isAlreadyNamed(member, newName)) {
+ result.addFatalError(
+ RefactoringCoreMessages.RenameRefactoring_another_name,
+ DartStatusContext.create(member));
+ return result;
+ }
+
+ // type can not have two members with same name
+ {
+ Type enclosingType = member.getDeclaringType();
+ TypeMember[] existingMembers = enclosingType.getExistingMembers(newName);
+ for (TypeMember existingMember : existingMembers) {
+ IPath resourcePath = enclosingType.getResource().getFullPath();
+ String message = Messages.format(
+ RefactoringCoreMessages.RenameRefactoring_enclosing_type_member_already_defined,
+ new Object[] {
+ enclosingType.getElementName(),
+ BasicElementLabels.getPathLabel(resourcePath, false),
+ newName});
+ result.addError(message, DartStatusContext.create(existingMember));
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public Change createChange(IProgressMonitor monitor) throws CoreException {
+ monitor.beginTask(RefactoringCoreMessages.RenameRefactoring_checking, 1);
+ try {
+ return new CompositeChange(getProcessorName(), changeManager.getAllChanges());
+ } finally {
+ monitor.done();
+ }
+ }
+
+ @Override
+ public final String getCurrentElementName() {
+ return member.getElementName();
+ }
+
+ @Override
+ public Object[] getElements() {
+ return new Object[] {member};
+ }
+
+ @Override
+ public int getSaveMode() {
+ return RefactoringSaveHelper.SAVE_ALL;
+ }
+
+ @Override
+ protected RefactoringStatus doCheckFinalConditions(
+ IProgressMonitor pm,
+ CheckConditionsContext context) throws CoreException {
+ try {
+ pm.beginTask("", 19); //$NON-NLS-1$
+ pm.setTaskName(RefactoringCoreMessages.RenameRefactoring_checking);
+ RefactoringStatus result = new RefactoringStatus();
+ // check new name
+ result.merge(checkNewElementName(getNewElementName()));
+ pm.worked(1);
+ // prepare references
+ pm.setTaskName(RefactoringCoreMessages.RenameRefactoring_searching);
+ prepareReferences(new SubProgressMonitor(pm, 3));
+ pm.setTaskName(RefactoringCoreMessages.RenameRefactoring_checking);
+ // analyze affected units (such as warn about existing compilation errors)
+ result.merge(analyzeAffectedCompilationUnits());
+ // check for possible conflicts
+ result.merge(analyzePossibleConflicts(new SubProgressMonitor(pm, 10)));
+ if (result.hasFatalError()) {
+ return result;
+ }
+ // OK, create changes
+ createChanges(new SubProgressMonitor(pm, 5));
+ return result;
+ } finally {
+ pm.done();
+ }
+ }
+
+ private void addDeclarationUpdate() throws CoreException {
+ SourceRange nameRange = member.getNameRange();
+ CompilationUnit cu = member.getCompilationUnit();
+ String editName = RefactoringCoreMessages.RenameRefactoring_update_declaration;
+ addTextEdit(changeManager.get(cu), editName, createTextChange(nameRange));
+ }
+
+ private void addReferenceUpdates(IProgressMonitor pm) throws DartModelException {
+ pm.beginTask("", references.size()); //$NON-NLS-1$
+ String editName = RefactoringCoreMessages.RenameRefactoring_update_reference;
+ for (SearchMatch match : references) {
+ CompilationUnit cu = match.getElement().getAncestor(CompilationUnit.class);
+ SourceRange matchRange = match.getSourceRange();
+ addTextEdit(changeManager.get(cu), editName, createTextChange(matchRange));
+ pm.worked(1);
+ }
+ }
+
+ private RefactoringStatus analyzeAffectedCompilationUnits() throws CoreException {
+ RefactoringStatus result = new RefactoringStatus();
+ result.merge(Checks.checkCompileErrorsInAffectedFiles(references));
+ return result;
+ }
+
+ private RefactoringStatus analyzePossibleConflicts(IProgressMonitor pm) throws CoreException {
+ pm.beginTask("Analyze possible conflicts", 3);
+ try {
+ RefactoringStatus result = new RefactoringStatus();
+ String newName = getNewElementName();
+ Type enclosingType = member.getAncestor(Type.class);
+ List<Type> subTypes = RenameAnalyzeUtil.getSubTypes(enclosingType);
+ Iterable<Type> enclosingAndSubTypes = Iterables.concat(
+ ImmutableSet.of(enclosingType),
+ subTypes);
+ // analyze top-level elements
+ pm.subTask("Analyze top-level elements");
+ {
+ CompilationUnitElement topLevelElement = RenameAnalyzeUtil.getTopLevelElementNamed(
+ Sets.<DartLibrary>newHashSet(),
+ member,
+ newName);
+ if (topLevelElement != null) {
+ DartLibrary shadowLibrary = topLevelElement.getAncestor(DartLibrary.class);
+ IPath libraryPath = shadowLibrary.getResource().getFullPath();
+ IPath resourcePath = topLevelElement.getResource().getFullPath();
+ // add warning for shadowing top-level declaration
+ {
+ String message = Messages.format(
+ RefactoringCoreMessages.RenameProcessor_topLevelDecl_shadowedBy_element,
+ new Object[] {
+ RenameAnalyzeUtil.getElementTypeName(topLevelElement),
+ newName,
+ BasicElementLabels.getPathLabel(resourcePath, false),
+ BasicElementLabels.getPathLabel(libraryPath, false),
+ RenameAnalyzeUtil.getElementTypeName(member)});
+ result.addWarning(message, DartStatusContext.create(topLevelElement));
+ }
+ // TypeMember shadows top-level element usage in enclosing type
+ {
+ List<SearchMatch> refs = RenameAnalyzeUtil.getReferences(topLevelElement);
+ for (SearchMatch ref : refs) {
+ if (SourceRangeUtils.intersects(ref.getSourceRange(), enclosingType.getSourceRange())) {
+ String message = Messages.format(
+ RefactoringCoreMessages.RenameProcessor_topLevelUsage_shadowedBy_element,
+ new Object[] {
+ RenameAnalyzeUtil.getElementTypeName(topLevelElement),
+ newName,
+ BasicElementLabels.getPathLabel(resourcePath, false),
+ BasicElementLabels.getPathLabel(libraryPath, false),
+ RenameAnalyzeUtil.getElementTypeName(member)});
+ result.addError(message, DartStatusContext.create(ref));
+ }
+ }
+ }
+ // top-level element shadows TypeMember usage in sub-type
+ // http://code.google.com/p/dart/issues/detail?id=1180
+ for (Type subType : subTypes) {
+ for (SearchMatch ref : references) {
+ if (SourceRangeUtils.intersects(ref.getSourceRange(), subType.getSourceRange())) {
+ String message = Messages.format(
+ RefactoringCoreMessages.RenameProcessor_typeMemberUsage_shadowedBy_topLevel,
+ new Object[] {
+ RenameAnalyzeUtil.getElementTypeName(member),
+ enclosingType.getElementName(),
+ member.getElementName(),
+ RenameAnalyzeUtil.getElementTypeName(topLevelElement),
+ newName,
+ BasicElementLabels.getPathLabel(resourcePath, false),
+ BasicElementLabels.getPathLabel(libraryPath, false)});
+ result.addError(message, DartStatusContext.create(ref));
+ }
+ }
+ }
+ }
+ }
+ // analyze supertypes
+ pm.subTask("Analyze supertypes");
+ {
+ Set<Type> superTypes = RenameAnalyzeUtil.getSuperTypes(enclosingType);
+ for (Type superType : superTypes) {
+ TypeMember[] superTypeMembers = superType.getExistingMembers(newName);
+ for (TypeMember superTypeMember : superTypeMembers) {
+ // add warning for hiding super-type TypeMember
+ {
+ IPath resourcePath = superType.getResource().getFullPath();
+ String message = Messages.format(
+ RefactoringCoreMessages.RenameProcessor_typeMemberDecl_shadowedBy_element,
+ new Object[] {
+ RenameAnalyzeUtil.getElementTypeName(superTypeMember),
+ superType.getElementName(),
+ newName,
+ BasicElementLabels.getPathLabel(resourcePath, false),
+ RenameAnalyzeUtil.getElementTypeName(member)});
+ result.addWarning(message, DartStatusContext.create(superTypeMember));
+ }
+ // add error for using hidden super-type TypeMember
+ {
+ List<SearchMatch> refs = RenameAnalyzeUtil.getReferences(superTypeMember);
+ for (SearchMatch ref : refs) {
+ for (Type subType : enclosingAndSubTypes) {
+ if (SourceRangeUtils.intersects(ref.getSourceRange(), subType.getSourceRange())) {
+ IPath resourcePath = superType.getResource().getFullPath();
+ String message = Messages.format(
+ RefactoringCoreMessages.RenameProcessor_typeMemberUsage_shadowedBy_element,
+ new Object[] {
+ RenameAnalyzeUtil.getElementTypeName(superTypeMember),
+ superType.getElementName(),
+ newName,
+ BasicElementLabels.getPathLabel(resourcePath, false),
+ RenameAnalyzeUtil.getElementTypeName(member)});
+ result.addError(message, DartStatusContext.create(ref));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ pm.worked(1);
+ // analyze [sub-]type members
+ pm.subTask("Analyze subtypes");
+ for (Type subType : enclosingAndSubTypes) {
+ // check for declared members of sub-types
+ if (!Objects.equal(subType, enclosingType)) {
+ TypeMember[] subTypeMembers = subType.getExistingMembers(newName);
+ for (TypeMember subTypeMember : subTypeMembers) {
+ IPath resourcePath = subType.getResource().getFullPath();
+ // add warning for hiding Renamed declaration
+ {
+ String message = Messages.format(
+ RefactoringCoreMessages.RenameTopRefactoring_elementDecl_shadowedBy_typeMember,
+ new Object[] {
+ RenameAnalyzeUtil.getElementTypeName(member),
+ RenameAnalyzeUtil.getElementTypeName(subTypeMember),
+ subType.getElementName(),
+ newName,
+ BasicElementLabels.getPathLabel(resourcePath, false)});
+ result.addWarning(message, DartStatusContext.create(subTypeMember));
+ }
+ // add error for hiding Renamed usage
+ {
+ List<Type> subTypes2 = RenameAnalyzeUtil.getSubTypes(subType);
+ subTypes2.add(subType);
+ for (SearchMatch ref : references) {
+ Type refEnclosingType = ref.getElement().getAncestor(Type.class);
+ if (subTypes2.contains(refEnclosingType)) {
+ String message = Messages.format(
+ RefactoringCoreMessages.RenameTopRefactoring_elementUsage_shadowedBy_typeMember,
+ new Object[] {
+ RenameAnalyzeUtil.getElementTypeName(member),
+ RenameAnalyzeUtil.getElementTypeName(subTypeMember),
+ subType.getElementName(),
+ newName,
+ BasicElementLabels.getPathLabel(resourcePath, false)});
+ result.addError(message, DartStatusContext.create(ref));
+ }
+ }
+ }
+ }
+ }
+ // check for local variables
+ for (Method method : subType.getMethods()) {
+ DartVariableDeclaration[] localVariables = method.getLocalVariables();
+ for (DartVariableDeclaration variable : localVariables) {
+ if (variable.getElementName().equals(newName)) {
+ IPath resourcePath = subType.getResource().getFullPath();
+ // add warning for hiding Renamed declaration
+ {
+ String message = Messages.format(
+ RefactoringCoreMessages.RenameTopRefactoring_elementDecl_shadowedBy_variable_inMethod,
+ new Object[] {
+ RenameAnalyzeUtil.getElementTypeName(member),
+ subType.getElementName(),
+ method.getElementName(),
+ BasicElementLabels.getPathLabel(resourcePath, false)});
+ result.addWarning(message, DartStatusContext.create(variable));
+ }
+ // add error for hiding Renamed usage
+ for (SearchMatch match : references) {
+ if (SourceRangeUtils.intersects(match.getSourceRange(), variable.getVisibleRange())) {
+ String message = Messages.format(
+ RefactoringCoreMessages.RenameTopRefactoring_elementUsage_shadowedBy_variable_inMethod,
+ new Object[] {
+ RenameAnalyzeUtil.getElementTypeName(member),
+ subType.getElementName(),
+ method.getElementName(),
+ BasicElementLabels.getPathLabel(resourcePath, false)});
+ result.addError(message, DartStatusContext.create(match));
+ }
+ }
+ }
+ }
+ }
+ }
+ pm.worked(1);
+
+ // OK
+ return result;
+ } finally {
+ pm.done();
+ }
+ }
+
+ private void createChanges(IProgressMonitor pm) throws CoreException {
+ pm.beginTask(RefactoringCoreMessages.RenameRefactoring_checking, 10);
+ changeManager.clear();
+ // update declaration
+ addDeclarationUpdate();
+ pm.worked(1);
+ // update references
+ addReferenceUpdates(new SubProgressMonitor(pm, 9));
+ pm.done();
+ }
+
+ private TextEdit createTextChange(SourceRange sourceRange) {
+ return new ReplaceEdit(sourceRange.getOffset(), sourceRange.getLength(), getNewElementName());
+ }
+
+ private void prepareReferences(final IProgressMonitor pm) throws CoreException {
+ references = RenameAnalyzeUtil.getReferences(member);
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698