/******************************************************************************* * Copyright (c) 2008, 2017 xored software, Inc. and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * xored software, Inc. - initial API and Implementation (Andrei Sobolev) *******************************************************************************/ package org.eclipse.dltk.tcl.internal.validators.checks; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.Assert; import org.eclipse.dltk.core.IScriptProject; import org.eclipse.dltk.core.builder.ISourceLineTracker; import org.eclipse.dltk.tcl.ast.StringArgument; import org.eclipse.dltk.tcl.ast.TclArgument; import org.eclipse.dltk.tcl.ast.TclCommand; import org.eclipse.dltk.tcl.definitions.Command; import org.eclipse.dltk.tcl.internal.validators.ICheckKinds; import org.eclipse.dltk.tcl.parser.ITclErrorReporter; import org.eclipse.dltk.tcl.parser.TclParserUtils; import org.eclipse.dltk.tcl.parser.TclVisitor; import org.eclipse.dltk.tcl.parser.definitions.DefinitionManager; import org.eclipse.dltk.tcl.parser.definitions.IScopeProcessor; import org.eclipse.dltk.tcl.validators.ITclCheck; import org.eclipse.osgi.util.NLS; public class CommandRedefinitionCheck implements ITclCheck { public CommandRedefinitionCheck() { } @Override public void checkCommands(final List<TclCommand> tclCommands, final ITclErrorReporter reporter, Map<String, String> options, IScriptProject project, final ISourceLineTracker sourceLineTracker) { final IScopeProcessor processor = DefinitionManager.getInstance() .createProcessor(); TclParserUtils.traverse(tclCommands, new TclVisitor() { Map<String, Integer> userCommands = new HashMap<>(); @Override public boolean visit(TclCommand tclCommand) { Assert.isNotNull(tclCommand); processor.processCommand(tclCommand); if (tclCommand.getDefinition() == null || !tclCommand.isMatched()) { return true; } if ("proc".equals(tclCommand.getDefinition().getName())) { Assert.isLegal(tclCommand.getArguments().size() >= 3); TclArgument nameArgument = tclCommand.getArguments().get(0); if (nameArgument instanceof StringArgument) { String current = ((StringArgument) nameArgument) .getValue(); current = processor.getQualifiedName(current); if (current.startsWith("::")) { current = current.substring(2); } Command[] definitions = processor .getCommandDefinition(current); if (definitions != null && definitions.length != 0) reporter.report( ICheckKinds.BUILTIN_COMMAND_REDEFINITION, "Built-in command redefinition", null, nameArgument.getStart(), nameArgument.getEnd(), ITclErrorReporter.WARNING); Set<String> names = userCommands.keySet(); for (String name : names) { if (name.equals(current)) { final String msg = NLS.bind( "Procedure {0} is already defined on line {1}", name, userCommands.get(name)); reporter.report( ICheckKinds.USER_COMMAND_REDEFINITION, msg, null, nameArgument.getStart(), nameArgument.getEnd(), ITclErrorReporter.WARNING); } } int start = tclCommand.getStart(); userCommands.put(current, sourceLineTracker.getLineNumberOfOffset(start)); } } return true; } @Override public void endVisit(TclCommand command) { processor.endProcessCommand(); } }); } }