8017611: Auto corrector for mistyped vm options
The auto corrector for mistyped vm options fuzzy-matches existing flags based on string similarity (Dice's coefficient). Reviewed-by: kvn, dsamersoff, hseigel, johnc
This commit is contained in:
parent
f93ee2a9dd
commit
7109e85e43
@ -849,7 +849,7 @@ bool Arguments::process_argument(const char* arg,
|
|||||||
arg_len = equal_sign - argname;
|
arg_len = equal_sign - argname;
|
||||||
}
|
}
|
||||||
|
|
||||||
Flag* found_flag = Flag::find_flag((char*)argname, arg_len, true);
|
Flag* found_flag = Flag::find_flag((const char*)argname, arg_len, true);
|
||||||
if (found_flag != NULL) {
|
if (found_flag != NULL) {
|
||||||
char locked_message_buf[BUFLEN];
|
char locked_message_buf[BUFLEN];
|
||||||
found_flag->get_locked_message(locked_message_buf, BUFLEN);
|
found_flag->get_locked_message(locked_message_buf, BUFLEN);
|
||||||
@ -870,6 +870,14 @@ bool Arguments::process_argument(const char* arg,
|
|||||||
} else {
|
} else {
|
||||||
jio_fprintf(defaultStream::error_stream(),
|
jio_fprintf(defaultStream::error_stream(),
|
||||||
"Unrecognized VM option '%s'\n", argname);
|
"Unrecognized VM option '%s'\n", argname);
|
||||||
|
Flag* fuzzy_matched = Flag::fuzzy_match((const char*)argname, arg_len, true);
|
||||||
|
if (fuzzy_matched != NULL) {
|
||||||
|
jio_fprintf(defaultStream::error_stream(),
|
||||||
|
"Did you mean '%s%s%s'?\n",
|
||||||
|
(fuzzy_matched->is_bool()) ? "(+/-)" : "",
|
||||||
|
fuzzy_matched->name,
|
||||||
|
(fuzzy_matched->is_bool()) ? "" : "=<value>");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow for commandline "commenting out" options like -XX:#+Verbose
|
// allow for commandline "commenting out" options like -XX:#+Verbose
|
||||||
|
@ -276,14 +276,14 @@ static Flag flagTable[] = {
|
|||||||
Flag* Flag::flags = flagTable;
|
Flag* Flag::flags = flagTable;
|
||||||
size_t Flag::numFlags = (sizeof(flagTable) / sizeof(Flag));
|
size_t Flag::numFlags = (sizeof(flagTable) / sizeof(Flag));
|
||||||
|
|
||||||
inline bool str_equal(const char* s, char* q, size_t len) {
|
inline bool str_equal(const char* s, const char* q, size_t len) {
|
||||||
// s is null terminated, q is not!
|
// s is null terminated, q is not!
|
||||||
if (strlen(s) != (unsigned int) len) return false;
|
if (strlen(s) != (unsigned int) len) return false;
|
||||||
return strncmp(s, q, len) == 0;
|
return strncmp(s, q, len) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search the flag table for a named flag
|
// Search the flag table for a named flag
|
||||||
Flag* Flag::find_flag(char* name, size_t length, bool allow_locked) {
|
Flag* Flag::find_flag(const char* name, size_t length, bool allow_locked) {
|
||||||
for (Flag* current = &flagTable[0]; current->name != NULL; current++) {
|
for (Flag* current = &flagTable[0]; current->name != NULL; current++) {
|
||||||
if (str_equal(current->name, name, length)) {
|
if (str_equal(current->name, name, length)) {
|
||||||
// Found a matching entry. Report locked flags only if allowed.
|
// Found a matching entry. Report locked flags only if allowed.
|
||||||
@ -301,6 +301,52 @@ Flag* Flag::find_flag(char* name, size_t length, bool allow_locked) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compute string similarity based on Dice's coefficient
|
||||||
|
static float str_similar(const char* str1, const char* str2, size_t len2) {
|
||||||
|
int len1 = (int) strlen(str1);
|
||||||
|
int total = len1 + (int) len2;
|
||||||
|
|
||||||
|
int hit = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < len1 -1; ++i) {
|
||||||
|
for (int j = 0; j < (int) len2 -1; ++j) {
|
||||||
|
if ((str1[i] == str2[j]) && (str1[i+1] == str2[j+1])) {
|
||||||
|
++hit;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 2.0f * (float) hit / (float) total;
|
||||||
|
}
|
||||||
|
|
||||||
|
Flag* Flag::fuzzy_match(const char* name, size_t length, bool allow_locked) {
|
||||||
|
float VMOptionsFuzzyMatchSimilarity = 0.7f;
|
||||||
|
Flag* match = NULL;
|
||||||
|
float score;
|
||||||
|
float max_score = -1;
|
||||||
|
|
||||||
|
for (Flag* current = &flagTable[0]; current->name != NULL; current++) {
|
||||||
|
score = str_similar(current->name, name, length);
|
||||||
|
if (score > max_score) {
|
||||||
|
max_score = score;
|
||||||
|
match = current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(match->is_unlocked() || match->is_unlocker())) {
|
||||||
|
if (!allow_locked) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_score < VMOptionsFuzzyMatchSimilarity) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the address of the index'th element
|
// Returns the address of the index'th element
|
||||||
static Flag* address_of_flag(CommandLineFlagWithType flag) {
|
static Flag* address_of_flag(CommandLineFlagWithType flag) {
|
||||||
assert((size_t)flag < Flag::numFlags, "bad command line flag index");
|
assert((size_t)flag < Flag::numFlags, "bad command line flag index");
|
||||||
|
@ -220,7 +220,8 @@ struct Flag {
|
|||||||
// number of flags
|
// number of flags
|
||||||
static size_t numFlags;
|
static size_t numFlags;
|
||||||
|
|
||||||
static Flag* find_flag(char* name, size_t length, bool allow_locked = false);
|
static Flag* find_flag(const char* name, size_t length, bool allow_locked = false);
|
||||||
|
static Flag* fuzzy_match(const char* name, size_t length, bool allow_locked = false);
|
||||||
|
|
||||||
bool is_bool() const { return strcmp(type, "bool") == 0; }
|
bool is_bool() const { return strcmp(type, "bool") == 0; }
|
||||||
bool get_bool() const { return *((bool*) addr); }
|
bool get_bool() const { return *((bool*) addr); }
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test TestUnrecognizedVMOptionsHandling
|
||||||
|
* @key gc
|
||||||
|
* @bug 8017611
|
||||||
|
* @summary Tests handling unrecognized VM options
|
||||||
|
* @library /testlibrary
|
||||||
|
* @run main/othervm TestUnrecognizedVMOptionsHandling
|
||||||
|
*/
|
||||||
|
|
||||||
|
import com.oracle.java.testlibrary.*;
|
||||||
|
|
||||||
|
public class TestUnrecognizedVMOptionsHandling {
|
||||||
|
|
||||||
|
public static void main(String args[]) throws Exception {
|
||||||
|
// The first two JAVA processes are expected to fail, but with a correct VM option suggestion
|
||||||
|
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
||||||
|
"-XX:+PrintGc",
|
||||||
|
"-version"
|
||||||
|
);
|
||||||
|
OutputAnalyzer outputWithError = new OutputAnalyzer(pb.start());
|
||||||
|
outputWithError.shouldContain("Did you mean '(+/-)PrintGC'?");
|
||||||
|
if (outputWithError.getExitValue() == 0) {
|
||||||
|
throw new RuntimeException("Not expected to get exit value 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
pb = ProcessTools.createJavaProcessBuilder(
|
||||||
|
"-XX:MaxiumHeapSize=500m",
|
||||||
|
"-version"
|
||||||
|
);
|
||||||
|
outputWithError = new OutputAnalyzer(pb.start());
|
||||||
|
outputWithError.shouldContain("Did you mean 'MaxHeapSize=<value>'?");
|
||||||
|
if (outputWithError.getExitValue() == 0) {
|
||||||
|
throw new RuntimeException("Not expected to get exit value 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
// The last JAVA process should run successfully for the purpose of sanity check
|
||||||
|
pb = ProcessTools.createJavaProcessBuilder(
|
||||||
|
"-XX:+PrintGC",
|
||||||
|
"-version"
|
||||||
|
);
|
||||||
|
OutputAnalyzer outputWithNoError = new OutputAnalyzer(pb.start());
|
||||||
|
outputWithNoError.shouldNotContain("Did you mean '(+/-)PrintGC'?");
|
||||||
|
outputWithNoError.shouldHaveExitValue(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user