@ -1234,6 +1234,8 @@ bool ValidateObjCClassPrefix(
// without any prefix at all (for legacy reasons).
// without any prefix at all (for legacy reasons).
bool has_prefix = file - > options ( ) . has_objc_class_prefix ( ) ;
bool has_prefix = file - > options ( ) . has_objc_class_prefix ( ) ;
bool have_expected_prefix_file = ! expected_prefixes_path . empty ( ) ;
const std : : string prefix = file - > options ( ) . objc_class_prefix ( ) ;
const std : : string prefix = file - > options ( ) . objc_class_prefix ( ) ;
const std : : string package = file - > package ( ) ;
const std : : string package = file - > package ( ) ;
@ -1267,30 +1269,10 @@ bool ValidateObjCClassPrefix(
return true ;
return true ;
}
}
// Check: Warning - Make sure the prefix is is a reasonable value according
// When the prefix is non empty, check it against the expected entries.
// to Apple's rules (the checks above implicitly whitelist anything that
if ( ! prefix . empty ( ) & & have_expected_prefix_file ) {
// doesn't meet these rules).
// For a non empty prefix, look for any other package that uses the prefix.
if ( ! prefix . empty ( ) & & ! ascii_isupper ( prefix [ 0 ] ) ) {
std : : cerr
< < " protoc:0: warning: Invalid 'option objc_class_prefix = \" "
< < prefix < < " \" ;' in ' " < < file - > name ( ) < < " '; "
< < " it should start with a capital letter. " < < std : : endl ;
std : : cerr . flush ( ) ;
}
if ( ! prefix . empty ( ) & & prefix . length ( ) < 3 ) {
// Apple reserves 2 character prefixes for themselves. They do use some
// 3 character prefixes, but they haven't updated the rules/docs.
std : : cerr
< < " protoc:0: warning: Invalid 'option objc_class_prefix = \" "
< < prefix < < " \" ;' in ' " < < file - > name ( ) < < " '; "
< < " Apple recommends they should be at least 3 characters long. "
< < std : : endl ;
std : : cerr . flush ( ) ;
}
// Look for any other package that uses the same (non empty) prefix.
std : : string other_package_for_prefix ;
std : : string other_package_for_prefix ;
if ( ! prefix . empty ( ) ) {
for ( std : : map < std : : string , std : : string > : : const_iterator i =
for ( std : : map < std : : string , std : : string > : : const_iterator i =
expected_package_prefixes . begin ( ) ;
expected_package_prefixes . begin ( ) ;
i ! = expected_package_prefixes . end ( ) ; + + i ) {
i ! = expected_package_prefixes . end ( ) ; + + i ) {
@ -1299,11 +1281,11 @@ bool ValidateObjCClassPrefix(
break ;
break ;
}
}
}
}
}
// Check: Warning - If the file does not have a package, check whether the non
// Check: Warning - If the file does not have a package, check whether the
// empty prefix declared is being used by another package or not.
// prefix was declared is being used by another package or not. This is
if ( package . empty ( ) & & ! prefix . empty ( ) ) {
// a special case for empty packages.
if ( package . empty ( ) ) {
// The file does not have a package and ...
// The file does not have a package and ...
if ( other_package_for_prefix . empty ( ) ) {
if ( other_package_for_prefix . empty ( ) ) {
// ... no other package has declared that prefix.
// ... no other package has declared that prefix.
@ -1340,10 +1322,32 @@ bool ValidateObjCClassPrefix(
expected_prefixes_path + " ). " ;
expected_prefixes_path + " ). " ;
return false ; // Only report first usage of the prefix.
return false ; // Only report first usage of the prefix.
}
}
} // !prefix.empty()
// Check: Warning - Make sure the prefix is is a reasonable value according
// to Apple's rules (the checks above implicitly whitelist anything that
// doesn't meet these rules).
if ( ! prefix . empty ( ) & & ! ascii_isupper ( prefix [ 0 ] ) ) {
std : : cerr
< < " protoc:0: warning: Invalid 'option objc_class_prefix = \" "
< < prefix < < " \" ;' in ' " < < file - > name ( ) < < " '; "
< < " it should start with a capital letter. " < < std : : endl ;
std : : cerr . flush ( ) ;
}
if ( ! prefix . empty ( ) & & prefix . length ( ) < 3 ) {
// Apple reserves 2 character prefixes for themselves. They do use some
// 3 character prefixes, but they haven't updated the rules/docs.
std : : cerr
< < " protoc:0: warning: Invalid 'option objc_class_prefix = \" "
< < prefix < < " \" ;' in ' " < < file - > name ( ) < < " '; "
< < " Apple recommends they should be at least 3 characters long. "
< < std : : endl ;
std : : cerr . flush ( ) ;
}
// Check: Warning - If the given package/prefix pair wasn't expected, issue a
// Check: Warning - If the given package/prefix pair wasn't expected, issue a
// warning suggesting it gets added to the file.
// warning suggesting it gets added to the file.
if ( ! expected_package_prefixes . empty ( ) ) {
if ( have_expected_prefix_file ) {
std : : cerr
std : : cerr
< < " protoc:0: warning: Found unexpected 'option objc_class_prefix = \" "
< < " protoc:0: warning: Found unexpected 'option objc_class_prefix = \" "
< < prefix < < " \" ;' in ' " < < file - > name ( ) < < " '; "
< < prefix < < " \" ;' in ' " < < file - > name ( ) < < " '; "
@ -1360,6 +1364,12 @@ bool ValidateObjCClassPrefix(
bool ValidateObjCClassPrefixes ( const std : : vector < const FileDescriptor * > & files ,
bool ValidateObjCClassPrefixes ( const std : : vector < const FileDescriptor * > & files ,
const Options & generation_options ,
const Options & generation_options ,
std : : string * out_error ) {
std : : string * out_error ) {
// Allow a '-' as the path for the expected prefixes to completely disable
// even the most basic of checks.
if ( generation_options . expected_prefixes_path = = " - " ) {
return true ;
}
// Load the expected package prefixes, if available, to validate against.
// Load the expected package prefixes, if available, to validate against.
std : : map < std : : string , std : : string > expected_package_prefixes ;
std : : map < std : : string , std : : string > expected_package_prefixes ;
if ( ! LoadExpectedPackagePrefixes ( generation_options ,
if ( ! LoadExpectedPackagePrefixes ( generation_options ,