blob: cf3a0e8ff651ad287ee87097b1ab0b272c2905e3 [file] [log] [blame]
/*
* Copyright (c) 2013, 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.command.analyze;
import com.google.common.collect.Lists;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
/**
* Command line options accepted by the {@link AnalyzerMain} entry point.
*/
public class AnalyzerOptions {
enum AnalyzerOutputFormat {
MACHINE
}
/**
* Create a new AnalyzerOptions object from the given list of command-line args.
*
* @param args
* @return
*/
public static AnalyzerOptions createFromArgs(String[] args) {
args = processArgs(args);
AnalyzerOptions options = new AnalyzerOptions();
CmdLineParser cmdLineParser = new CmdLineParser(options);
for (int i = 0, len = args.length; i < len; i++) {
try {
cmdLineParser.parseArgument(args);
} catch (CmdLineException e) {
String msg = e.getMessage();
if (e.getMessage().endsWith(" is not a valid option")) {
String option = msg.substring(1);
int closeQuote = option.indexOf('\"');
option = option.substring(0, closeQuote);
List<String> newArgs = Lists.newArrayList();
for (String arg : args) {
if (arg.equals(option)) {
System.out.println("Ignoring unrecognized flag: " + arg);
continue;
}
newArgs.add(arg);
}
args = newArgs.toArray(new String[newArgs.size()]);
cmdLineParser = new CmdLineParser(options);
continue;
}
}
break;
}
return options;
}
/**
* Print the tool usage to the given stream.
*
* @param out
*/
public static void printUsage(PrintStream out) {
AnalyzerOptions bean = new AnalyzerOptions();
CmdLineParser parser = new CmdLineParser(bean);
parser.setUsageWidth(120);
parser.printUsage(out);
}
private static String[] processArgs(String[] args) {
List<String> result = new ArrayList<String>();
for (String arg : args) {
if (arg.isEmpty()) {
continue;
}
if (arg.indexOf('=') != -1) {
String[] strs = arg.split("=");
for (int i = 0; i < strs.length; i++) {
result.add(strs[i]);
}
} else {
result.add(arg);
}
}
return result.toArray(new String[result.size()]);
}
@Option(name = "--machine", // deprecated - used --format=machine instead
usage = "Print errors in a format suitable for parsing")
private boolean machineFormat = false;
@Option(name = "--format", //
usage = "Print errors in the specified format")
private AnalyzerOutputFormat outputFormat = null;
@Option(name = "--help", //
aliases = {"-h"}, //
usage = "Prints this help message")
private boolean showHelp = false;
@Option(name = "--version", //
usage = "Print the analyzer version")
private boolean showVersion = false;
@Option(name = "--dart-sdk", //
metaVar = "<dir>")
// usage = "The path to the Dart SDK") // don't show in help
private File dartSdkPath = null;
@Option(name = "--use-dart2js-libraries")
// usage = "Use the same resolution of dart: URI's as dart2js (defaults to the resolution used by the VM)") // don't show in help
private boolean useDart2jsPaths = false;
@Option(name = "--enable-async")
private boolean enableAsync = false;
@Option(name = "--enable-enum")
private boolean enableEnum = false;
@Option(name = "--verbose", //
aliases = {"-v"})
// TODO(devoncarew): document this flag when it is supported
//usage = "Print verbose information while analyzing")
private boolean enableVerbose = false;
@Option(name = "--package-root", //
aliases = {"-p"}, //
metaVar = "<dir>", //
usage = "The path to the package root")
private File packageRootPath = null;
@Option(name = "--use-package-map")
private boolean usePackageMap = false;
@Option(name = "--package-warnings", //
aliases = {"--show-package-warnings"}, // deprecated alias
usage = "Show warnings from package: imports")
private boolean showPackageWarnings = false;
@Option(name = "--batch", //
aliases = {"-batch"})
private boolean batch = false;
@Option(name = "--warnings", //
aliases = {"--show-sdk-warnings"} // deprecated alias
)
private boolean showSdkWarnings = false;
@Option(name = "--fatal-warnings")
private boolean warningsAreFatal = false;
// TODO(devoncarew): this is unused, and is only for dartc compatibility
@Option(name = "--fatal-type-errors")
private boolean fatalTypeError = false;
@Option(name = "--ignore-unrecognized-flags")
private boolean ignoreUnrecognizedFlags;
@Option(name = "--no-hints",//
usage = "Do not show hint results")
private boolean disableHints = false;
@Option(name = "--enable_type_checks")
// usage = "Check types in constant evaluation") // don't show in help
private boolean enableTypeChecks = false;
@Option(name = "--perf",//
usage = "Print performance statistics")
private boolean perf = false;
@Option(name = "--diagnostic-colors")
private boolean diagnosticColors = false; // ignored for now
@Option(name = "--warm-perf")
// usage = "Print both cold and warm performance statistics") // don't show in help
private boolean warmPerf = false;
@Argument
private final String sourceFile = null;
public AnalyzerOptions() {
super();
}
/**
* Return the path to the dart SDK.
*/
public File getDartSdkPath() {
return dartSdkPath;
}
/**
* @return whether hint results (e.g. type inference based information and pub best practices)
* should not be reported.
*/
public boolean getDisableHints() {
return disableHints;
}
/**
* Return {@code true} if support for async syntax should be enabled.
*/
public boolean getEnableAsync() {
return enableAsync;
}
/**
* Return {@code true} if support for enum syntax should be enabled.
*/
public boolean getEnableEnum() {
return enableEnum;
}
/**
* Return {@code true} if analysis should treat type mismatches found during constant evaluation
* as errors.
*/
public boolean getEnableTypeChecks() {
return enableTypeChecks;
}
public boolean getMachineFormat() {
return machineFormat || outputFormat == AnalyzerOutputFormat.MACHINE;
}
/**
* @return the package-root path, if specified
*/
public File getPackageRootPath() {
return packageRootPath;
}
/**
* @return whether performance statistics should be printed.
*/
public boolean getPerf() {
return perf;
}
/**
* @return whether SDK warnings should be reported
*/
public boolean getShowPackageWarnings() {
return showPackageWarnings;
}
/**
* @return whether SDK warnings should be reported
*/
public boolean getShowSdkWarnings() {
return showSdkWarnings;
}
/**
* @return whether we should print out the analyzer version
*/
public boolean getShowVersion() {
return showVersion;
}
/**
* Returns the file passed to the analyzer.
*/
public String getSourceFile() {
return sourceFile;
}
/**
* Return {@code true} if the analyzer should use the same resolution of dart: URI's as dart2js,
* or {@code false} if it should use the resolution used by the VM.
*
* @return {@code true} if the analyzer should use the dart2js paths when they are available
*/
public boolean getUseDart2jsPaths() {
return useDart2jsPaths;
}
/**
* Return whether package: urls should be resolved by querying pub for a package map. This uses
* pub's list-package-dirs command.
*
* @return whether to use an alternative package resolver
*/
public boolean getUsePackageMap() {
return usePackageMap;
}
/**
* @return whether both cold and warm performance statistics should be printed
*/
public boolean getWarmPerf() {
return warmPerf;
}
/**
* Return whether warnings are reported as fatal errors. This is only useful for batch mode.
*
* @return whether warnings are reported as fatal errors
*/
public boolean getWarningsAreFatal() {
return warningsAreFatal;
}
/**
* Initialize the SDK path.
*/
public void initializeSdkPath() {
// current directory, one level up, and a "sdk" directory below us
final String[] searchPath = new String[] {".", "..", "sdk"};
if (dartSdkPath == null) {
try {
File cwd = new File(".").getCanonicalFile();
for (String path : searchPath) {
File dir = new File(cwd, path);
dir = dir.getCanonicalFile();
if (isSDKPath(dir)) {
dartSdkPath = dir;
return;
}
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
public void setDartSdkPath(File dartSdkPath) {
this.dartSdkPath = dartSdkPath;
}
public void setWarningsAreFatal(boolean value) {
this.warningsAreFatal = value;
}
/**
* Return {@code true} if the analyzer should be run in batch mode, {@code false} otherwise.
* <p>
* (In batch mode, command line arguments are received through stdin and returning pass/fail
* status through stdout. Batch mode is used in test execution.)
*/
public boolean shouldBatch() {
return batch;
}
/**
* Returns {@code true} to indicate printing the help message.
*/
public boolean showHelp() {
return showHelp;
}
private boolean isSDKPath(File sdkDirectory) {
if (!sdkDirectory.exists()) {
return false;
}
if (!sdkDirectory.getName().equals("dart-sdk") && !sdkDirectory.getName().equals("sdk")) {
return false;
}
// check for (dart-sdk|sdk)/version
if (new File(sdkDirectory, "version").exists()) {
return true;
}
// check for (dart-sdk|sdk)/lib/_internal/libraries.dart
File libDir = new File(sdkDirectory, "lib");
if (libDir.exists()) {
File _internalDir = new File(libDir, "_internal");
if (_internalDir.exists()) {
if (new File(_internalDir, "libraries.dart").exists()) {
return true;
}
}
}
return false;
}
}